我是Prolog的新手,作为练习我想制作一个列表反转谓词。它使用我之前创建的add_tail
谓词 - 某些部分可能是多余的,但我不在乎:
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].
当我在append
谓词中使用invert
时,它运行正常,但如果我使用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
我的错误究竟是什么?谢谢!
答案 0 :(得分:2)
很难确定你的确切的错误,但是add_tail/3
的前两个条款(带有剪切的条款)是错误的(除非我误解了谓词应该是什么做)。这个名称有点误导,你应该关心你有多余的代码。
list_back([], B, [B]).
list_back([X|Xs], B, [X|Ys]) :-
list_back(Xs, B, Ys).
这是您add_tail/3
定义中invert/2
的替代品。但是你可能知道,这不是一个非常聪明的方法来反转列表。如何做的教科书示例:
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).
答案 1 :(得分: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/3
中使用list_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].
答案 2 :(得分:1)
首先尝试最常见的查询,以查看最常见情况下存在哪些解决方案:
?- add_tail(X, Y, Z).
得出单一答案:
X = Z,
Y = []
这可能不是你打算在这里定义的关系。
提示:!/0
通常会破坏代码的所有逻辑属性,包括在各个方向使用谓词的功能。
答案 3 :(得分:0)
基于之前的答案" @ mat"问题是前两行中的残留
您的谓词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
代码中进行简单修改后,我获得了您的预期结果
<强>码强>
% 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
我希望这篇文章可以帮助你解释谓词内部是如何完成的。
享受
答案 4 :(得分:0)
add_tail / 3的第一个子句将 list 作为第二个参数,因此它永远不会应用于您的测试用例。然后我们留下2个条款(简化)
add_tail([A],H,[A,H]):-!.
add_tail([A|B],H,[A|C]) :- add_tail(B,H,C).
您可以看到我们错过了空列表的匹配子句作为第一个参数。当然,追加/ 3代替 这样的匹配。