我试图理解为什么代码1可以正常工作,但是代码2输出false:
remove(X,[],[]).
remove(X,[X|Y],Z):-remove(X,Y,Z). % [X|Y] is the input list
remove(X,[F|Y],[F|Z]):-remove(X,Y,Z). % code 1
remove(X,[],[]).
remove(X,[X|Y],Z):-remove(X,Y,Z). % [X|Y] is the input list
remove(X,[F|Y],Z):-remove(X,Y,[F|Z]). % code 2
答案 0 :(得分:3)
您提供的两个谓词-code 1
和 code 2
-都破了。
您没有注意到的原因是:查询。
#1 ) 考虑在this previous "answer"中显示的查询:
?- remove(x, [x,a,b,c,x,d], R). R = [a,b,c,d] % okay
好吗?是的,但是可能会有更多答案。让我们按; ↵!
; R = [a,b,c,x,d] % BAD! ; R = [x,a,b,c,d] % BAD! ; R = [x,a,b,c,x,d] % BAD! ; false. % (no more answers)
这三个答案无效,因为每个R
都包含一些x
。
最下面的样子:不要只看一些一些查询答案。查看所有查询答案!
#2 ) Prolog程序包含不同类型的子句:事实,规则和查询。
查询是程序中非常重要的部分(如果不是最重要的部分)。
查询既是文档又是规范。最重要的是,它们使您可以将程序开发的“机械”部分委派给Prolog处理器。
那要写哪些查询?
以最普遍的查询开头:
?- remove(A,B,C).
您希望成功的查询:
?- remove(x,[x,a,x,p],[a,p]). % x is first element
?- remove(x,[a,x,p,x],[a,p]). % x is last element
?- remove(x,[a,x,p],[a,p]).
您期望失败的查询
?- \+ (remove(x,[a,x,p],Ls), dif(Ls,[a,p])).
地面查询:
?- remove(x,[],[]).
非地面查询(带有变量的查询):
?- remove(X,[a,b,a,c,d,c,a,b],Xs).
最重要的是: 没有查询,您不是在编写代码,而是在编写文本。
#3 )现在,我们来解决code 1
:看看两个递归子句!
remove(X,[X|Y],Z) :- remove(X,Y,Z). remove(X,[F|Y],[F|Z]) :- remove(X,Y,Z).
第一个规则将X
与第一个列表[X|Y]
相关。好吧!
第二个规则既不X
也不[F|Y]
[F|Z]
。不好!</ p>
通过向第二个子句添加prolog-dif目标dif/2
,我们可以建立该连接。
#4 )完成!这是谓词remove/3
的完整代码:
remove(_X, [], []). remove(X, [X|Y], Z) :- remove(X, Y, Z). remove(X, [F|Y], [F|Z]) :- dif(X, F), remove(X, Y, Z).
答案 1 :(得分:1)
考虑查询,
?- remove(x, [x,a,b,c,x,d], R).
代码2的问题在于,在某些时候,提取第二个列表中的所有元素后,它变为空。此时,在递归时,唯一可能的选择是第一个子句,因为第2和第3个子句要求列表具有头,但不是因为它为空。
因此,它尝试与第一个执行统一。现在,前两个谓词很好,但最后一个有问题。
即,它尝试统一[] = [d, c, b, a | _free_ ]
。这是不可能的,因为[]不是“自由变量”
但是我的术语可能是错误的...但是我相信本质就在那里。