为什么我在删除所需数字的列表后再次获得原始文件?

时间:2017-03-10 14:24:30

标签: list prolog

我试图实现一个prolog规则,它从某个列表中删除数字X并返回没有X的列表。然而,在得到正确的结果之后,我得到了原始列表的替代结果,我也弄清楚我的代码中的问题在哪里。

remove1(X,[],[]).
remove1(X,[X|T],T).
remove1(X,[H|T],[H|R]):-
    X \= H,
    remove1(X,T,R).
remove1(X,[H|T],[H|T]):-
    \+member(X,T).

2 个答案:

答案 0 :(得分:1)

让我们用一个例子回答这个问题。假设我们从2移除[1,2,3]。然后Prolog将对此进行评估:

remove1(2,[1,2,3],R):
    fail. % clause 1
    fail. % clause 2
    2 \= 1, remove1(2,[2,3],R'): % clause 3
        fail. % clause 1
        R = [1,3] % clause 2
        2 \= 2... fail. % clause 3
        \+member(2,[3]),R=[1,2,3] % clause 4
    \+member(2,[2,3])... fail. % clause 4

(以粗体显示的答案)

因此,一旦Prolog找到第一个答案,它就会回溯,检查2是否是尾T=[3]的成员(它不是),因此回复(基于最后一个条款) [1,2,3]也是一个答案。

这让我想知道为什么你添加了最后一个条款。如果找不到2,Prolog会回答列表。所以该计划:

remove1(X,[],[]).
remove1(X,[X|T],T).
remove1(X,[H|T],[H|R]):-
    X \= H,
    remove1(X,T,R).

就足够了。

如果您希望查询仅在已删除一次时成功,则还应删除第一个查询。所以:

remove1_force(X,[X|T],T).
remove1_force(X,[H|T],[H|R]):-
    X \= H,
    remove1(X,T,R).

两个谓词都只会删除列表中{em} {<1>}的首次。所以X。只会给出一个答案:remove1_force(1,[1,2,3,1,2,3],R)

答案 1 :(得分:1)

基本上,第一个和最后一个条款是不必要的。最后一个条款是错误结果的来源。

这似乎是另一本教科书&#34;谓词,通常称为select/3。 [Sterling&amp; Shapiro](第67页)中的教科书定义与SWI-Prolog library implementation相同,如下所示:

%!  select(?Elem, ?List1, ?List2)
%
%   Is true when List1, with Elem removed, results in List2.

select(X, [X|Tail], Tail).
select(Elem, [Head|Tail], [Head|Rest]) :-
    select(Elem, Tail, Rest).

您会注意到它不需要任何辅助谓词,并且是真正的关系。试试例如:

?- select(X, [1,2,3], R).

甚至:

?- select(X, List, Rest), numbervars(List).

numbervars/1只是使解决方案更具可读性)

这个定义是一般的,因为......好吧,它是一般定义。第一个子句执行&#34;选择&#34;,第二个子句定义递归步骤。

[Sterling&amp; Shapiro]:Sterling L,Shapiro EY。 Prolog的艺术:高级编程技术。 MIT出版社; 1994年。