简单的Prolog从列表中删除

int*_*tar 5 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).
Run Code Online (Sandbox Code Playgroud)

当我测试它时,我首先得到一个很好的答案(即删除了所有的X.)然后回溯为我提供了列表的所有其他变体,其中删除了一些或没有X的实例.

为什么会这样?为什么H == X的情况会落到最后一个子句?

fal*_*lse 6

当你(==)/2用于比较时,你需要在第三个规则中相反,即(\==)/2.另一方面,这样的定义不再是纯粹的关系.要看到这一点,请考虑deleteall([X],Y,Zs), X = Y.

对于纯粹的关系,我们需要(=)/2dif/2.许多Prolog如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).
Run Code Online (Sandbox Code Playgroud)

看看答案deleteall([X,Y],Z,Xs)!

编辑(四年后):

更有效率,但在相同的纯静脉中,这可以使用if_/3和写(=)/3:

deleteall([], _X, []).
deleteall([E|Es], X, Ys0) :-
   if_( E = X, Ys0 = Ys, Ys0 = [E|Ys] ),
   deleteall(Es, X, Ys).
Run Code Online (Sandbox Code Playgroud)


Aas*_*set 2

最后一个子句表示,当X从列表中删除时,头元素可能会保留(与其值无关)。Prolog 可以在任何它认为合适的时候使用这个子句,无论前一个子句中的条件是否为真,或者如果另一个子句失败,或者如果你指示它这样做(例如通过;在 top-级别以获得下一个解决方案)。如果您添加一个条件,即 head 元素可能不等于X,它应该可以工作。

编辑:删除了我最初打开的不正确的断言。

  • -1。Prolog 子句按照从左到右、自上而下的顺序执行,尽管解释器可能会在失败时回溯到后续子句。 (2认同)