查找列表中的唯一项目

时间:2016-11-06 08:53:05

标签: prolog

我正在尝试编写一条规则来决定项X是否恰好出现在列表L中的一个。

unique(X, [X|T]):- !, \+ member(X, T).
unique(X, [_|T]):- unique(X, T).

该规则适用于确定值是否在列表中是唯一的,但是当我尝试使用unique(X, [1,2,3,1,3,2,5,4,3,8]).在列表中获取唯一值时,它只返回false.我期望的是这个(比如member(X, list).

X = 5 ;
X = 4 ;
X = 8 ;

我是一个完全的初学者,我不知道我做错了什么。

3 个答案:

答案 0 :(得分:7)

你一直在使用剪切和不安全的否定形式。两者都必须非常谨慎地使用。立即解决的问题是保护您的程序免受不适合使用的程序:

unique(X, Xs) :-
   iwhen(ground(X+Xs), your_unique(X, Xs)).

这使用iwhen/2,类似于when/2,但不会延迟:

:- meta_predicate iwhen(+, 0).

iwhen(Cond, G_0) :-
   when(Cond, ( Called = true, G_0 ) ),
   ( var(Called) -> throw(error(instantiation_error,_)) ; true ).

以上适用于提供when/2的系统。以下是任何符合ISO标准的系统:

iwhen(Cond, G_0) :-
   (  when_condition(Cond)
   -> ( Cond -> G_0 ; throw(error(instantiation_error,_)) )
   ;  throw(error(domain_error(when_condition, Cond),_))
   ).

when_condition(C) :-
   var(C),
   !,
   throw(error(instantiation_error,_)).
when_condition(ground(_)).
when_condition(nonvar(_)).
when_condition(?=(_, _)).
when_condition(( A, B )) :-
   when_condition(A),
   when_condition(B).
when_condition(( A ; B )) :-
   when_condition(A),
   when_condition(B).

另一方面,它总是非常令人沮丧地接收实例化错误,而不是真正的答案。所以,让我们的程序真正纯粹!

你的第二条规则

unique(X, [_|Es]) :-
   unique(X, Es).

以声明方式从右向左阅读(:-

  

如果X是列表Es的唯一元素,则X是列表[_|Es]的唯一元素。

换句话说:每当我知道X中的Es是唯一的时,Es中的任何元素也是唯一的。这个结论不正确,考虑通过X来扩展列表!你需要一些额外的条件。此外,您的第一条规则需要重新制定。这使用non_member/2

unique(X, [X|Es]) :-
   non_member(X, Es).
unique(X, [E|Es]) :-
   dif(X, E),
   unique(X, Es).

以下是使用tfilter/3的另一种方式:

unique(X, Es) :-
   tfilter(=(X), Es, [_]).

效率最高的可能是使用if_/3的{​​{1}}:

library(reif)

答案 1 :(得分:4)

以下是使用nth0/4(或select/3的简单解决方案,如@false所指出的那样):

unique(X, L) :-
    nth0(_, L, X, R),
    \+ member(X, R).

nth0/4第四个参数R是已移除元素L的列表X。我们只是检查X是否不在R

更好的版本

unique(X, L) :-
    nth0(_, L, X, R),
    maplist(dif(X), R).

这解决了@false指出的问题,但由于你是初学者,我怀疑你对此很感兴趣。

这具有在以下情况下工作的优势:

?- unique(b, [X, Y, a]).
X = b,
dif(Y, b) ;
Y = b,
dif(X, b) ;
false.

答案 2 :(得分:0)

这听起来像是一个家庭作业问题。

尝试这样的事情。

unique(M, L) :- member(M, L), count(M, L, 1).  
count(M, [H|T], C) :- M = H, count(M, T, C1), C is C + 1.
...

完成后,这给...

?- unique(X, [1,2,3,1,3,2,5,4,3,8]).
X = 5 ;
X = 4 ;
X = 8 ;
false.

编辑: 由于答案已经给出......这里是光滑的。

unique(Item, List) :-
  select(Item, List, L2),
  \+ member(Item, L2).