作为起点,我们来看看@CapelliC 对equal_elements/2 的第二个实现:
equal_elements([], []).
equal_elements([X|Xs], Ys) :-
select(X, Ys, Zs),
equal_elements(Xs, Zs).
上面的实现为像这样的查询留下了无用的选择点:
?- equal_elements([1,2,3],[3,2,1]).
true ; % succeeds, but leaves choicepoint
false.
我们能做什么?我们可以通过使用来解决效率问题
selectchk/3 而不是
select/3,但这样做我们会失去logical-purity! 我们可以做得更好吗?
我们可以!
介绍selectd/3,一个逻辑纯谓词,结合了selectchk/3 的确定性和select/3 的纯度。 selectd/3 基于
if_/3 和 (=)/3:
selectd(E,[A|As],Bs1) :-
if_(A = E, As = Bs1,
(Bs1 = [A|Bs], selectd(E,As,Bs))).
selectd/3 可以直接替代select/3,所以使用起来很容易!
equal_elementsB([], []).
equal_elementsB([X|Xs], Ys) :-
selectd(X, Ys, Zs),
equal_elementsB(Xs, Zs).
让我们看看它的实际效果!
?- equal_elementsB([1,2,3],[3,2,1]).
true. % succeeds deterministically
?- equal_elementsB([1,2,3],[A,B,C]), C=3,B=2,A=1.
A = 1, B = 2, C = 3 ; % still logically pure
false.
编辑 2015-05-14
如果谓词,则 OP 不具体
应该强制项目发生在双方
相同的多重性。
equal_elementsB/2 是这样的吗,如这两个查询所示:
?- equal_elementsB([1,2,
3,2,
3],[
3,
3,2 ,1,2])。
真的。
?- equal_elementsB([1,2,
3,2,
3],[
3,
3,2 ,1,2,
3])。
错误。
如果我们希望第二个查询成功,我们可以通过使用元谓词以逻辑上纯粹的方式放宽定义
tfilter/3 和
具体化不平等dif/3:
equal_elementsC([],[]).
equal_elementsC([X|Xs],Ys2) :-
selectd(X,Ys2,Ys1),
tfilter(dif(X),Ys1,Ys0),
tfilter(dif(X),Xs ,Xs0),
equal_elementsC(Xs0,Ys0).
让我们像上面一样运行两个查询,这次使用equal_elementsC/2:
?- equal_elementsC([1,2,
3,2,
3],[
3,
3,2 ,1,2])。
真的。
?- equal_elementsC([1,2,
3,2,
3],[
3,
3,2 ,1,2,
3])。
是的。
编辑 2015-05-17
事实上,equal_elementsB/2 不会在以下情况下普遍终止:
?- equal_elementsB([],Xs),假的。 % 普遍终止
错误的。
?- equal_elementsB([_],Xs),假的。 % 给出了一个答案,但是......
%%% 永远等待 % ...
不会普遍终止
但是,如果我们翻转第一个和第二个参数,我们会得到终止!
?- equal_elementsB(Xs,[]), 假的。 % 普遍终止
错误的。
?- equal_elementsB(Xs,[_]), 假的。 % 普遍终止
错误的。
受an answer given by @AmiTavory 的启发,我们可以通过“锐化”解决方案集来改进equal_elementsB/2 的实现,如下所示:
equal_elementsBB(Xs,Ys) :-
相同长度(Xs,Ys),
equal_elementsB(Xs,Ys)。
为了检查非终止是否消失,我们将使用两个谓词的查询头对头:
?- equal_elementsB([_],Xs),假的。
%%% 永远等待 %
不会普遍终止
?- equal_elementsBB([_],Xs),假的。
错误的。 %
普遍终止
请注意,相同的“技巧”不适用于equal_elementsC/2,
因为解决方案集的大小是无限的(对于所有感兴趣的最微不足道的实例除外)。