你在正确的轨道上...... 保持纯洁---这很容易!
使用具体的相等谓词=/3 和dif/3 与if_/3 结合使用,在Prolog union for A U B U C 中实现:
=(X, Y, R) :- X == Y, !, R = true.
=(X, Y, R) :- ?=(X, Y), !, R = false. % syntactically different
=(X, Y, R) :- X \= Y, !, R = false. % semantically different
=(X, Y, R) :- R == true, !, X = Y.
=(X, X, true).
=(X, Y, false) :-
dif(X, Y).
% dif/3 is defined like (=)/3
dif(X, Y, R) :- X == Y, !, R = false.
dif(X, Y, R) :- ?=(X, Y), !, R = true. % syntactically different
dif(X, Y, R) :- X \= Y, !, R = true. % semantically different
dif(X, Y, R) :- R == true, !, X \= Y.
dif(X, Y, true) :- % succeed first!
dif(X, Y).
dif(X, X, false).
if_(C_1, Then_0, Else_0) :-
call(C_1, Truth),
functor(Truth,_,0), % safety check
( Truth == true -> Then_0 ; Truth == false, Else_0 ).
基于这些谓词,我们构建了一个具体的成员谓词list_item_isMember/3。它在语义上与@false 的memberd_truth/3 等价。我们重新排列参数顺序,因此列表是第一个参数。这将启用 first-argument 索引,从而防止留下无用的选择点,因为 memberd_truth/3 会创建。
list_item_isMember([],_,false).
list_item_isMember([X|Xs],E,Truth) :-
if_(E = X, Truth = true, list_item_isMember(Xs,E,Truth)).
list_set([],[]).
list_set([X|Xs],Ys) :-
if_(list_item_isMember(Xs,X), Ys = Ys0, Ys = [X|Ys0]),
list_set(Xs,Ys0).
一个简单的查询表明所有多余的答案都已消除并且目标成功没有留下任何选择点:
?- list_set([1,2,3,4,1,2,3,4,1,2,3,1,2,1],Xs)。
Xs = [4,3,2,1]。 %
确定性地成功
编辑 2015-04-23
@Ludwig 对set/2 的回答启发了我,如下所示:
set([],[]).
set([H|T],[H|T1]) :- subtract(T,[H],T2), set(T2,T1).
SWI-Prolog 的内置谓词subtract/3 可以是非单调的,这可能会限制其使用。 list_item_subtracted/3 是它的单调变体:
list_item_subtracted([],_,[]).
list_item_subtracted([A|As],E,Bs1) :-
if_(dif(A,E), Bs1 = [A|Bs], Bs = Bs1),
list_item_subtracted(As,E,Bs).
list_setB/2 类似于set/2,但基于list_item_subtracted/3---不是subtract/3:
list_setB([],[]).
list_setB([X|Xs1],[X|Ys]) :-
list_item_subtracted(Xs1,X,Xs),
list_setB(Xs,Ys).
以下查询比较list_set/2 和list_setB/2:
?- list_set([1,2,3,4,1,2,3,4,1,2,3,1,2,1], Xs)。
Xs = [4,3,2,1]。 %
确定性地成功
?- list_setB([1,2,3,4,1,2,3,4,1,2,3,1,2,1],Xs)。
Xs = [1,2,3,4]。 %
确定性地成功
?- list_set(Xs,[a,b])。
Xs = [a,b]
; Xs = [a,b,b]
; Xs = [a,b,b,b]
... %
不会普遍终止
?- list_setB(Xs,[a,b])。
Xs = [a,b]
; Xs = [a,b,b]
; Xs = [a,b,b,b]
... %
不会普遍终止