我试图实现一个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).
答案 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年。