2011-03-02 48 views
0

我想通過例子來理解序言。我寫了一段代碼,但沒有按照預期的方式工作,我無法找到故障。用列表操作

list([]). 


test([],_,_).     
test([Child|List],B,C) :- 
    append([Child],B,C), 
    test(List,B,C). 

testme :- 
     list(Final), 
     test([1,2,3],Final,Result), 
     write(Result). 

從代碼中我需要的功能Result應該是輸入列表的反轉。當我跟蹤這段代碼時,我在C中發現了輸入列表的反轉,但它沒有被返回。

我知道使用reverse函數我可以很容易地找到列表的反轉,但我的興趣不在於找到相反的地方,而是瞭解這個代碼和prolog的工作。所以請有人能告訴我我的錯在哪裏以及在這段代碼中需要做些什麼修改才能正常工作。

回答

1

首先讓我們看看爲什麼你的代碼不工作。

test([],_,_).     
test([Child|List],B,C) :- 
    append([Child],B,C), 
    test(List,B,C). 

您試圖用兩個子句定義一個遞歸謂詞。 這個謂詞的參數是:輸入列表(1),中間列表(2)和最終結果(3)。

因此,您的第一個條款是錯誤的。 假設您的輸入列表只是一個空列表。結果應該是一個空的列表。但是在你的第一個條款中,你現在正在離開第三個參數。要麼它已經被綁定(在這種情況下沒有用)或者它是無界的,因此它會保持這種狀態。

第二個子句處理遞歸。它將輸入列表的第一個元素添加到中間列表的前面,生成另一箇中間列表。 現在您再次執行遞歸調用測試。但請注意,現在三個參數被實例化了!所以你將無法將其他項目追加到最終列表中。

這裏去您的測試/ 3謂詞修改爲你所期望的工作:

test([],List,List). 
test([Child|List],B,D) :- 
    append([Child],B,C), 
    test(List,C,D). 

現在第一款只是統一了第二個和第三個參數。 因此,在我們的第一個測試用例(空輸入列表)中,回想第二個參數也是一個空列表,所以第三個參數也是一個空列表=>正確的。

現在爲遞歸子句。 它將採用輸入列表的第一個元素,並將其附加到中間列表中,並將其統一到新的變量上。 現在我們進入遞歸步驟,但現在我們使用該列表(C)作爲中間列表。 這在遞歸時會建立輸出列表,現在綁定到D,這是我們用作輸出的東西。

當你只是追加每次一元到中間列表中,你可能已經擺脫了附加的的東西,如:

test([],List,List). 
test([Child|List],B,C) :- 
    test(List,[Child|B],C). 
+0

中的代碼,非常感謝您提供了這樣一個描述性答案。它有很多幫助。 :) – anilonwebs 2011-03-02 14:07:42

0

Prolog規則只能「返回」值(因爲參數和返回值之間確實沒有區別)通過將它們與參數統一起來。假設你想要一個基於累加器的reverse操作,您將需要三個參數來test,它應該作爲如果它被寫爲:

test(A, B, C) :- reverse(A, A2), append(A2, B, C). 

具有test一個隱含的附加操作將使得遞歸更容易編寫。此外,請注意,您可以將append([A], B, C)編寫爲C = [A | B](或者用[A | B]替換C)。

+0

謝謝你的建議,但我想用遞歸也。我對結果不感興趣,但它應該正常工作我想知道其故障運行背後的原因。我試圖修改我的代碼,但它也不起作用。我已經更新了問題部分 – anilonwebs 2011-03-02 10:08:25