2012-04-07 177 views
3

我正在編寫一個程序,我需要列出一個列表,其中包含表示產品的數字對和給定數字的總和。序言 - 遞歸列表構建

現在我有一個函數,我可以指定多少次我想添加一個列表到列表中,這個列表將在後面用完整的功能進行擴展。

這是我有:

s1(0, X). 
s1(Q, X) :- 
    N is Q - 1, 
    multiply(2, 3, Y), 
    A = Y , 
    add(2, 3, Z), 
    B = Z, 
    addToEnd([A], [B], X), 
    s1(N,X). 

multiply(A, B, C):- 
    C is A * B. 

add(A, B, C) :- 
    C is A + B. 

addToEnd([], L, L). 
addToEnd([H|T], L2, [H|L3]) :- 
    addToEnd(T, L2, L3). 

然而,當我如運行s1(2,X),我得到[6,5]回來,那麼沒有別的,它只是掛起。當我運行s1(0,X),我得到true,然後false當我打;

任何人都可以幫助我嗎?我看不到我做錯了什麼,我覺得它應該工作!

爲了澄清我怎麼覺得這應該工作: 我打電話s1(2,X). N = 1[6,5]加入X([[6,5]]) s1(1,X). N=0列出,[6,5]添加到列表中X ([[6,5],[6,5]]) s1(0,X). X = [[6,5],[6,5]]

回答

5

因此,有很多事情要說。首先,就像在大多數聲明性語言中一樣,變量不能真正改變值。

這也就意味着,X = 1.將統一1X如你所期望的,但如果你在你的查詢(X = 1, X = 2.)之後添加X = 2.,Prolog的會說false。其原因是你不能統一12X已真正成爲1,因此X不能統一爲2

儘管和Haskell,Ocaml等不同,您可以部分綁定一個變量,如X = h(Y).。然後,您可以進一步將它統一爲X = h(a(Z)).,而您不能以之前提到的語言(其中變量實際上只是值的別名)。

他爲什麼告訴我你想知道的一切?那麼,這是你的主要問題。您首先將X綁定到[6, 5],然後期望進一步將其綁定到其他某些東西。一旦一個變量被研磨(即它本身不包含任何自由變量),就不能再次改變它的值。

所以這裏你的遞歸不會做任何事情,但最終會證明X錯誤。但是,這並不是因爲您每次都會以相同的參數呼叫addToEnd/3[6],[5][6, 5])。

這就是說,讓我們看看我們如何可以改善您的代碼。

首先,一句話:

multiply(2, 3, Y), 
A = Y , 
add(2, 3, Z), 
B = Z, 
addToEnd([A], [B], X), 

可以寫

multiply(2, 3, Y), 
add(2, 3, Z), 
addToEnd([Y], [Z], X), 

沒有丟失任何信息,因爲你不要再使用AB

現在,讓我們忘掉addToEnd/3了一會兒,想想你想要什麼。

如果輸入s1(0, Q),你真的要Q留免費的嗎?因爲那是你目前所說的。在這種情況下,綁定Q[]會更有意義。另外,你會很快看到,這將成爲一個很好的遞歸基礎案例。

s1(0, []). 

是一條捷徑說

s1(0, Q) :- Q = []. 

因爲Prolog的確實條款頭統一(部分:-之前)。

然後,我就騙一點,但它會只是留下清晰。你可以聲明打算從s1(4, Q)s1(5, Q)當你想到Q可舉辦一些微積分的一個更大的價值。

在這裏,我們可以指出如下:

s1(N, [SomeCalculus|Q]) :- 
    PreviousN is N - 1, 
    s1(PreviousN, Q). 

現在,我們只需要提供一個值SomeCalculus

s1(N, [SomeCalculus|Q]) :- 
    PreviousN is N - 1, 
    X is 2 * 3, 
    Y is 2 + 3, 
    SomeCalculus = [X, Y], 
    s1(PreviousN, Q). 

或者,如果您是正確的,我們可以直接寫:

s1(N, [[X, Y]|Q]) :- 
    PreviousN is N - 1, 
    X is 2 * 3, 
    Y is 2 + 3, 
    s1(PreviousN, Q). 

所以完整的程序將是:

現在
s1(0, []). 
s1(N, [[X, Y]|Q]) :- 
    PreviousN is N - 1, 
    X is 2 * 3, 
    Y is 2 + 3, 
    s1(PreviousN, Q). 

,如果你測試,你可能此話的程序循環,就像你當你點擊;關鍵。這是因爲序言認爲第二條款可以適用於0 了。

因此,讓我們再次修改程序:

s1(0, []). 
s1(N, [[X, Y]|Q]) :- 
    N > 0, 
    PreviousN is N - 1, 
    X is 2 * 3, 
    Y is 2 + 3, 
    s1(PreviousN, Q). 

現在一切都很好。

我希望這可以幫助您更好地理解如何通過遞歸構建適當的謂詞。我並沒有花太多時間來糾正你的謂詞,因爲我對變量的散漫應該已經告訴了你很多關於它的錯誤。

+0

非常感謝這一點,它確實有幫助。道歉爲什麼我敢肯定的是我的代碼中的基本錯誤,我是新的prolog,並來自C,Java等,這是一個非常不同的思維方式。 – XavierNuquos 2012-04-08 09:40:17

+0

@Mog:非常好!你真的有老師的天賦! – CapelliC 2012-04-08 10:48:38

+0

@chac:謝謝:) – m09 2012-04-08 10:54:14