Prolog 序言:查找重复项并将其放入列表中

Prolog 序言:查找重复项并将其放入列表中,prolog,Prolog,大家好。不明白为什么prolog谓词将所有重复项放入我的新列表中。F.e.我必须挑选所有的副本: ?- duplicates([a, b, a, a, d, d], R). R = [a, d] 我编写了这个序言程序: duplicates([], []). duplicates([First|Rest], NewRest) :- not(member(First, Rest)), duplicates(Rest, NewRest). duplicates([First

大家好。不明白为什么prolog谓词将所有重复项放入我的新列表中。F.e.我必须挑选所有的副本:

?- duplicates([a, b, a, a, d, d], R). 
R = [a, d] 
我编写了这个序言程序:

duplicates([], []).
duplicates([First|Rest], NewRest) :- 
    not(member(First, Rest)), 
    duplicates(Rest, NewRest).
duplicates([First|Rest], [First|NewRest]) :- 
    member(First, Rest), 
    duplicates(Rest, NewRest).
但它的回报是:

R = [a, a] .
我想我需要在某处放一个(!)标志,但我不明白,在哪里。有什么建议吗?

试试这个:

duplicates([], []).
duplicates([First|Rest], NewRest) :- 
    \+ member(First, Rest),
    duplicates(Rest, NewRest).
duplicates([First|Rest], NewRest) :- 
    duplicates(Rest, NewRest),
    member(First, NewRest).
duplicates([First|Rest], [First|NewRest]) :- 
    member(First, Rest), 
    duplicates(Rest, NewRest),
    \+ member(First, NewRest).

?- duplicates([a, b, a, a, d, d], R).
R = [a, d] ;
false.
我选择了一个不需要切割的版本(代码)!)。我还添加了另一条规则:
NewRest
中的元素只能出现一次。注意:
NewRest
中的成员资格只有在统一了所有条目后才能进行测试。

library()为您的问题提供了一个简洁的解决方案

重复(L,D):-findall(K,(聚合(计数,成员(K,L),C),C>1),D)。
-重复项([a,b,a,a,d,d],R)。
R=[a,d]。

显然,它比@Raubsauger的好答案更容易理解,而且不是在每个序言中都能找到。

请使用标准的
\+/1
谓词,而不是旧的和不推荐的
not/1
谓词。谢谢您的提示,我已经十年没有用prolog编写代码了。我不应该使用任何prolog库。@wollenS:我同意,库(聚合)是一个野兽,但希望您同意member/2也是一个库(列表)成员,尽管与聚合/3相比,自己编写要容易得多。对于Prolog新手来说,一个优化的member/2谓词是不容易发现的…编写自己的成员非常容易,所以这里没什么大不了的,伙计们展示了一个使用member的解决方案。