所以我有以下谓词,它以符号列表作为第一个参数,然后输出这个列表并删除所有重复项:
removeDups([], []).
removeDups([H|T], [H|T1]) :-
subtract(T, [H], T2),
removeDups(T2, T1).
它按预期工作,但我不确定如何理解它。
到目前为止我所理解的是:
T2
?T2
的临时值存储到T1
?我很困惑这里到底发生了什么,所以任何帮助都会非常感激!
答案 0 :(得分:2)
谓词减法/ 3描述了第三个参数是没有第二个参数元素的第一个参数的关系,例如:
removeDups([],[]).
removeDups / 2的第一条规则是基本情况:
removeDups([H|T], [H|T1]) :- % the head of list 1 is in the head of list 2
subtract(T, [H], T2), % T2 is the tail of list 1 without H
removeDups(T2,T1). % T1 is a duplicate free T2
您可以将其读作:没有重复项的空列表是空列表。第二个规则是关系的一般情况,其中第一个列表不为空。
T2
因此,减法/ 3的目标描述了一个列表H
,其中包含除T
T2
之外的所有元素。由于通过递归,列表[]
变得越来越短,您不可避免地会以基本案例 ?- X=1, subtract([1,2,3],[X],L).
L = [2,3],
X = 1
?- subtract([1,2,3],[X],L), X=1.
L = [2,3],
X = 1
结束。这是第一条规则所描述的。从程序上讲,您需要基本案例,以便您的谓词可以终止。但是,正如@repeat所指出的,如果前两个参数包含自由变量,则使用subtract / 3可能会有问题。请考虑以下示例:
?- X=2, subtract([1,2,3],[X],L).
L = [1,3],
X = 2
?- subtract([1,2,3],[X],L), X=2.
no
可是:
removeDups([],[]).
removeDups([H|T], [H|T1]) :-
safe_subtract(T, [H], T2),
removeDups(T2,T1).
safe_subtract(As,Bs,Xs) :-
( ground(As+Bs) ->
subtract(As,Bs,Xs) ;
throw(error(instantiation_error,_))).
因此,如评论中所建议的那样,测试这些论点以进行充分的实例化是一个好主意:
{{1}}
答案 1 :(得分:1)
此过程指出removeDups(L,L1)
:
L
和L1
都是包含至少一个元素的列表,每个列表的头部(H
)与另一个列表的头部统一,然后{{3使用第一个参数的列表尾部(T
)和仅包含头部的列表调用。此过程将第三个参数(T2
)与包含T
不带H
元素的列表统一起来。然后,对removeDups/3
的递归调用将相同的算法应用于结果列表(没有H
)。递归调用至少有一个元素小于原始列表L
。从递归调用返回时,T1应该没有重复(并且H
也不在其中)。但是,由于removeDups的第三个参数是[H|T1]
,调用者将在第三个参数H
中作为第三个列表的头部。