allsame([]).
allsame([X]).
allsame([X,X|Z]) :-
allsame([X|Z]).
如何更改以获得以下结果?
alldifferent(L): The elements in L are all different.
?- alldifferent([a, b, b, c, d]).
false
?- alldifferent([a, b, c, d, e]).
true
答案 0 :(得分:6)
首先,让我们先看一下allsame/1
的定义。对于给定的列表,
你正在建立这样的平等:
[ A, B, C, D ... ]
A = B, B = C, C = D, ... chain pattern
所以你正在建立一系列平等。还有另一种表达方式,通过引用一个公共变量来代替:
[ A, B, C, D ... ]
A = V, B = V, C = V, D = V, ... star pattern
这最常见地表达为:
allsame_bis(L) :-
maplist(=(_), L).
或者,更多的增长,不使用经常定义的maplist/2
:
allsame_ter(L) :-
allsame_with(L, _).
allsame_with([], _).
allsame_with([X|Xs], V) :-
X = V, % could be moved into the head
allsame_with(Xs, V).
现在,你说,你"想要关联"这到alldifferent/1
,这使情况更加复杂。请注意,alldifferent/1
并非直接否定您的财产。那将是:
notallsame(L) :-
phrase((..., [A,B], {dif(A,B)}, ...), L),
有两个直接连续的元素是不同的。
为了完整性,这里有一个版本可以避免notallsame([1,2,3])
之类的查询的多余答案:
notallsame_bis(L) :-
phrase((all(=(A)),[A,B], {dif(A,B)}, ...), L).
首先是一系列相同的元素,然后是一个不同的元素。
all//1
和... //1
为defined elsewhere。
但回到不同的/ 2。平等关系是可传递的,它允许我们做一些快捷方式,无论是做链还是做星。但是不同是不可传递的。所以我们现在要在所有可能的对之间建立差异关系dif/2
。总的来说,我们需要 n 2- n / 2许多dif/2
目标。嘿,让我们高兴我们仍然可以利用交换性,否则我们将不得不支付两倍以上。
alldifferent([]).
alldifferent([X|Xs]) :-
maplist(dif(X), Xs),
alldifferent(Xs).
此关系建立dif/2
,如此:
[ A, B, C, D, E ... ]
dif(B,A), dif(C,A), dif(D,A), dif(E,A), ... maplist(dif(A),[B,C,D,E ...])
dif(C,B), dif(D,B), dif(E,B), ... maplist(dif(B), [C,D,E ...])
dif(D,C), dif(E,C), ... maplist(dif(C), [D,E ...])
dif(E,D), ... maplist(dif(D), [E ...])
这是另一个版本,可能看起来更诱人。事实上,它与您的原始程序有一定的相似之处。不是吗?
alldifferent_bis([]).
alldifferent_bis([_]).
alldifferent_bis([A,B|Xs]) :-
dif(A,B),
alldifferent_bis([A|Xs]),
alldifferent_bis([B|Xs]).
最后,我们可以使用a higher order definition使用以下定义:
alldifferent_ter(L) :-
pairwise(dif,L).
allsame_quater(L) :-
pairwise(=,L).
如果您因任何原因无法使用dif/2
,请使用安全的ISO Prolog近似iso_dif/2
。它会尽可能频繁地(安全地)成功,但是当可能发生安全故障时可能会产生错误。想想alldifferent_bis([_,a,a])
。
答案 1 :(得分:0)
这是一种方式:
all_different( Xs ) :-
all_different(Xs,[])
.
all_different( [] , _ ) . % if the source list is exhausted, success!
all_different( [X|_] , S ) :- % if the list is non-empty
member(X,S ) , % - if we've already seen X
! , % - we cut and fail:
fail % The list has duplicates
. %
all_different( [X|Xs] , S ) :- % otherwise, we simply recurse down,
all_different( Xs , [X|S] ) % prepending X to the "already seen" list.
. % Easy!
另一种方式:
all_different( Xs ) :- setof( X , member(X,Xs), Xs ) .
第三种方式:
all_different( Xs ) :-
msort(Xs,S) ,
check_uniqueness(S)
.
check_uniqueness([]) .
check_uniqueness([X,X|_]) :- !, fail .
check_uniqueness([_|Xs]) :- check_uniqueness(Xs) .
第四种方式:
all_different( Xs ) :-
findall( X , (append(Pfx,[X|Sfx],Xs),(member(X,Pfx);member(X,Sfx))) , [] )
.
有多种方法可以做到这一点......有些方法比其他方式更有效。
答案 2 :(得分:0)
另一种方法:
all_different(Xs) :-
sort(Xs, Sorted),
msort(Xs, Sorted).
SWI-Prolog式模式声明:
%! all_different(+Xs:list) is semidet.