有人可以帮助我改变这个以符合这个更新的要求吗?
定义一个谓词
strikeDuplicates(X,Y)
,当且仅列出Y
时,它会成功 如果要删除每个元素的第二次和随后的出现,则获得 来自列表X
。 (您可以将strikeDuplicates (X,Y)
视为列表X
而不重复 是列表Y
。)当strikeDuplicates/2
是X
时,strike(X,Y,Z)
谓词无法正常工作 未绑定的变量。
两天前我问了一个类似的问题:
定义谓词
Z
,当且仅当列表X
成功时才成功 如果要从列表Y
中删除所有出现的元素strike/3
,则获取。该 当Y
是未绑定的变量时,strike( _ , [] , [] ) . strike( X , [X|T] , Z ) :- strike(X,T,Z) . strike( X , [A|T] , [A|Z] ) :- dif(X,A) , strike(X,T,Z) . dif(X,A).
谓词不能正常工作。
没有人帮助我,所以我必须自己做。答案是这样的:
{{1}}
答案 0 :(得分:1)
嗯,简单的方法是使用内置的谓词setof/3
,但我怀疑这不是你教授想要的。
考虑一两秒钟的问题。明确的问题陈述通常很有帮助(在Prolog中通常是解决方案本身):
要使源列表成为 set (唯一元素)而不是 bag (允许复制),您必须
一旦你做完了,你就得到了理想的结果。
这是一个提示:一个非常常见的prolog习语是使用带有累加器的辅助谓词。帮助器谓词通常具有相同的仿函数,但是具有不同的 arity 。例如,要对列表中的值求和(sum/2
),我们可以使用带有累加器的帮助器sum/3
,其中加上0:
sum(Xs,N) :- sum(Xs,0,N).
sum([],S,S).
sum([N|Ns],T,S) :-
T1 is T+N,
sum(Ns,T1,S)
.
在计算出最终值之前,您会注意到结果是否延迟。
您需要做类似的事情,但使用[empty] 列表作为累加器,将使用您发现的唯一值进行扩展。
另一个提示:内置谓词member/2
将检查一个术语是否是列表的成员。它是写的
member(X,[X|Xs]).
member(X,[_|Xs]) :- member(X,Xs).
所以member(2,[1,2,3])
为true
而member(2,[1,3])
为false
。
相反,可以使用member/2
通过回溯连续返回列表中的每个元素:member(X,[1,2,3])
生成
X = 1 ;
X = 2 ;
X = 3 ;
false
鉴于这两个概念,您应该能够找到解决方案。回来向我们展示您的代码,我们可以帮助您。还有一个小gotcha
,但我相信你会弄明白的。
答案 1 :(得分:1)
不保留顺序的简单解决方案是:
strike_duplicates([], []).
strike_duplicates([X| Xs], List) :-
( member(X, Xs) ->
strike_duplicates(Xs, List)
; List = [X| Tail],
strike_duplicates(Xs, Tail)
).
要保留顺序,您需要在遍历列表时跟踪到目前为止找到的元素。解决方案是:
strip_duplicates(List, Set) :-
strip_duplicates(List, [], Set).
strip_duplicates([], _, []).
strip_duplicates([X| Xs], Found, List) :-
( member(X, Found) ->
strip_duplicates(Xs, Found, List)
; List = [X| Tail],
strip_duplicates(Xs, [X| Found], Tail)
).
谓词member/2
通常是内置谓词或可用作库谓词。如有必要,请检查Prolog系统文档。