我正在尝试编写一条规则来决定项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 ;
我是一个完全的初学者,我不知道我做错了什么。
答案 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).