简单的Prolog从列表中删除
(这不是一个课程问题,只是我个人的学习。) 我试图在Prolog中做一个练习,从列表中删除元素。这是我的密码:简单的Prolog从列表中删除,prolog,prolog-dif,Prolog,Prolog Dif,(这不是一个课程问题,只是我个人的学习。) 我试图在Prolog中做一个练习,从列表中删除元素。这是我的密码: deleteall([],X,[]). deleteall([H|T],X,Result) :- H==X, deleteall(T,X,Result). deleteall([H|T],X,[H|Result]) :- deleteall(T,X,Result). 当我测试它时,我首先得到了一个很好的答案(即删除了所有的X),但随后回溯为我提供了列表的所有其他变体
deleteall([],X,[]).
deleteall([H|T],X,Result) :-
H==X,
deleteall(T,X,Result).
deleteall([H|T],X,[H|Result]) :- deleteall(T,X,Result).
当我测试它时,我首先得到了一个很好的答案(即删除了所有的X),但随后回溯为我提供了列表的所有其他变体,其中一些或没有删除X的实例
为什么会这样?为什么H==X的情况会出现在最后一个子句中?最后一个子句说,当从列表中删除
X
时,head元素可能会保留(与其值无关)。Prolog可以在其认为合适的任何时候使用该子句,而不依赖于前一子句中的条件是否正确,如果另一个子句失败,或者如果您指示它这样做(例如,通过在顶层发出;
,以获得下一个解决方案)。如果添加head元素可能不等于X
的条件,则它应该可以工作
编辑:删除了我最初打开时使用的错误断言。当您使用(==)/2
进行比较时,您需要在第三条规则中使用相反的断言,即(\==)/2
。另一方面,这样的定义不再是纯粹的关系。要看到这一点,请考虑<代码> DeleTALALL([X],Y,ZS),X= Y.< /代码>
对于纯关系,我们需要(=)/2
和dif/2
。许多开场白,如SWI、YAP、B、SICStus,都提供了dif/2
deleteall([],X,[]).
deleteall([H|T],X,Result) :-
H=X,
deleteall(T,X,Result).
deleteall([H|T],X,[H|Result]) :-
dif(H,X),
deleteall(T,X,Result).
查看删除所有([X,Y],Z,Xs)
的答案
编辑(四年后):
效率更高,但同样纯粹,可以使用和(=)/3
:
deleteall([], _X, []).
deleteall([E|Es], X, Ys0) :-
if_( E = X, Ys0 = Ys, Ys0 = [E|Ys] ),
deleteall(Es, X, Ys).
哦出于某种原因,我认为是这样的。(也就是说,清单算在内了。)这就解释了我面临的许多问题。Prolog子句是按照从左到右、自上而下的顺序执行的,尽管解释器在失败时可能会返回到以下子句中。子句的顺序并不是完全无序的。它们是按固定顺序考虑的。但你的观点是正确的:只要没有在你的从句中,每一个从句都会给出它的答案。只有不终止和错误才能隐藏进一步的答案。@larsmans:我删除了第一句话。中间的句子可能不完全正确;请随意编辑。@larsmans:谢谢。至少,我第一句话的开头是正确的:“我已经有一段时间没有做任何序言了。”——)谢谢interstar询问如何删除,我也在做同样的练习。我以前在prolog中没有使用过==运算符。我理解你的解决办法。我们可以通过将第一句中的X替换为u来改进,以避免单例变量。我们也应该放!第二和第三种情况下的操作员。