5

(这不是课程作业问题。只是我自己的个人学习。)

我正在尝试在 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。)但随后回溯为我提供了列表的所有其他变体,其中一些或没有删除 X 的实例。

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

4

2 回答 2

6

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

对于纯关系,我们需要(=)/2dif/2。SWI、YAP、B、SICStus 等许多 Prolog 都提供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).

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

编辑(四年后):

更有效,但同样纯粹,这可以用if_/3and来写(=)/3

deleteall([], _X, []).
deleteall([E|Es], X, Ys0) :-
   if_( E = X, Ys0 = Ys, Ys0 = [E|Ys] ),
   deleteall(Es, X, Ys).
于 2011-06-22T14:43:08.787 回答
2

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

编辑:删除了我最初打开的错误断言。

于 2011-06-22T14:30:01.837 回答