2016-01-25 69 views
1

我是新來的Prolog和作爲一個練習,我想做一個列表反轉謂詞。它使用add_tail謂我前面—做了一些零件可能是多餘的,但我不在乎:爲什麼我的Prolog謂詞反轉/ 2不起作用?

add_tail(A, [], A) :- 
    !. 
add_tail([A|[]], H, [A,H]) :- 
    !. 
add_tail([A|B], H, [A|C]) :- 
    add_tail(B,H,C). 

它的工作原理相同,內置謂詞append/3

?- add_tail([a,b,c], d, A). 
A = [a, b, c, d]. 

?- append([a,b,c], [d], A). 
A = [a, b, c, d]. 

當我在使用appendinvert謂語,它工作正常,但如果我用add_tail,它失敗:

invert([], []). 
invert([A|B], C) :- 
    invert(B, D), 
    append(D, [A], C). 

invert2([], []). 
invert2([A|B], C) :- 
    invert2(B, D), 
    add_tail(D, A, C). 

?- invert([a,b,c,d], A). 
A = [d, c, b, a]. 

?- invert2([a,b,c,d], A). 
false.       % expected answer A = [d,c,b,a], like above 

我的錯誤究竟是什麼?謝謝!

回答

2

執行add_tail/3確實不是完全按照您的預期行事。 考慮:

 
?- append([], [d], Xs). 
Xs = [d]. 

?- add_tail([], d, Xs). 
false. 

這是壞...但它變得更糟糕!甚至有更多的問題與您提供的代碼:

  • 使用(!)/0你不必要限制你的謂詞的多功能性。

  • 即使[A|[]]也許是正確的,它混淆了您的代碼。改爲使用[A]

  • add_tail對於在多個方向上工作的謂詞而言是一個糟糕的名稱。

  • 變量名稱可能會更好!爲什麼不使用更多描述性名稱,如As

    再次看看您在add_tail/3的最後一項中使用的變量!

     
    add_tail([A|B], H, [A|C]) :- 
        add_tail(B, H, C). 
    

    考慮改進的變量名:

     
    add_tail([A|As], E, [A|Xs]) :- 
        add_tail(As, E, Xs). 
    

我建議重新開始,像這樣:

 
list_item_appended([], X, [X]). 
list_item_appended([E|Es], X, [E|Xs]) :- 
    list_item_appended(Es, X, Xs). 

讓我們把list_item_appended/3list_reverted/2使用!

 
list_reverted([], []). 
list_reverted([E|Es], Xs) :- 
    list_reverted(Es, Fs), 
    list_item_appended(Fs, E, Xs). 

示例查詢:

?- list_reverted([a,b,c,d], Xs). 
Xs = [d, c, b, a]. 
1

首先嚐試的最一般的查詢,看看哪些解決方案在最一般的情況下存在:

?- add_tail(X, Y, Z). 

得到的唯一答覆:

X = Z, 
Y = [] 

這可能不是你想要定義的關係這裏。

提示:!/0通常會破壞您的代碼的所有邏輯屬性,包括在所有方向上使用謂詞的能力。

+0

S(X)對更一般的用途將重心轉移。 – repeat

2

這是很難找準你確切錯誤,但add_tail/3前兩個條款,與削減的,是錯誤的(除非我誤解了什麼謂語應該做的事)。名稱已經有點誤導了,你應該注意你有多餘的代碼。

list_back([], B, [B]). 
list_back([X|Xs], B, [X|Ys]) :- 
    list_back(Xs, B, Ys). 

這是你的invert/2定義一個下拉更換爲您add_tail/3。但是,正如你可能知道的那樣,這並不是一個反轉列表的非常聰明的方式。如何做到這一點的典型例子:根據「@mat」的前面的回答

list_rev(L, R) :- 
    list_rev_1(L, [], R). 

list_rev_1([], R, R). 
list_rev_1([X|Xs], R0, R) :- 
    list_rev_1(Xs, [X|R0], R). 
0

問題是殘留在頭兩行

您的謂語add_tail不像append因爲

append我得到這個

| ?- append(X,Y,Z). 
Z = Y, 
X = [] ? ; 
X = [_A], 
Z = [_A|Y] ? ; 
X = [_A,_B], 
Z = [_A,_B|Y] ? ; 
X = [_A,_B,_C], 
Z = [_A,_B,_C|Y] ? ; 
X = [_A,_B,_C,_D], 
Z = [_A,_B,_C,_D|Y] ? ; 
X = [_A,_B,_C,_D,_E], 
Z = [_A,_B,_C,_D,_E|Y] ? ;y 

,不幸與UR add_tail我得到個是導致

| ?- add_tail(X,Y,Z). 
Z = X, 
Y = [] ? ; 
X = [_A], 
Z = [_A|Y] ? ; 
X = [_A|_B], 
Y = [], 
Z = [_A|_B] ? ; 
X = [_A,_B], 
Z = [_A,_B|Y] ? ; 
X = [_A,_B|_C], 
Y = [], 
Z = [_A,_B|_C] ? 
X = [_A,_B,_C], 
Z = [_A,_B,_C|Y] ? y 
yes 

後在add_tail代碼的簡單變型I獲得的預期的結果

代碼

% add_tail(A,[],A):-! . comment 

add_tail([],H,H) :-!. 
add_tail([A|B],H,[A|C]) :- add_tail(B,H,C). 

測試add_tail

| ?- add_tail(X,Y,Z). 

    Z = Y, 
    X = [] ? ; 
    X = [_A], 
    Z = [_A|Y] ? ; 
    X = [_A,_B], 
    Z = [_A,_B|Y] ? ; 
    X = [_A,_B,_C], 
    Z = [_A,_B,_C|Y] ? ; 
    X = [_A,_B,_C,_D], 
    Z = [_A,_B,_C,_D|Y] ? ; 
    X = [_A,_B,_C,_D,_E], 
    Z = [_A,_B,_C,_D,_E|Y] ? y 
    yes 

finaly

我測試烏爾invert謂詞沒有修改

| ?- invert([_A,_B,_C],L). 
L = [_C,_B,_A] ? ; 
no 

我希望這篇文章可以幫助您解釋謂詞如何完成內部

享受

0

add_tail的第一條/ 3有一個列表作爲第二個參數,所以它不會適用於你的測試用例。然後,我們只剩下2項條款(簡體)

add_tail([A],H,[A,H]):-!. 
add_tail([A|B],H,[A|C]) :- add_tail(B,H,C). 

你可以看到,我們錯過了空列表作爲第一個參數匹配的條款。當然,追加/ 3而不是已有這樣的匹配。