首先,让我们看看您对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。
但回到 alldifferent/2。等式关系是可传递的,它允许我们做一些捷径,要么做链,要么做星。但是不同是不及物的。所以我们现在必须在所有可能的对之间建立差异关系dif/2。总的来说,我们需要 n2-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])。