如果您所说的“conjunction”是指“交集”,那么您应该查看 SWI-Prolog
library(lists)
中
intersection/3
谓词的实现。它包含剪枝,但如果您不介意所有选择点,可以将它们留下来。
?- intersection([a,b,c,a],[a,v,c],I).
I = [a, c, a].
当然,即使在库谓词中,这也不起作用,因为您需要使用带有当前定义的
集合。(如果只有第一个参数是一个集合,则足够了。)
您可以使用
sort/2
谓词创建集合:如果第一个参数是带有重复的列表,则第二个参数将是一个没有重复的排序列表,例如:
?- sort([a,b,c,a], S1), intersection(S1, [a,v,c], I).
S1 = [a, b, c],
I = [a, c].
或者也许:
?- sort([a,b,c,a], S1), intersection(S1, [a,v,c,c,a,c], I).
S1 = [a, b, c],
I = [a, c].
?- sort([a,b,c,a,b,c,a,b,c], S1), intersection(S1, [a,v,c,c,a,c], I).
S1 = [a, b, c],
I = [a, c].
如果您对两个参数进行排序,您可以使用
library(ordsets)
中基于
oset_int/3
实现的
ord_intersection/3
。
?- sort([a,b,c,a], S1), sort([a,v,c,c,a,c], S2), ord_intersection(S1, S2, I).
S1 = [a, b, c],
S2 = [a, c, v],
I = [a, c].
重要的是,
oset_int/3
在其实现中不使用任何剪枝。但它假定第一个和第二个参数是按
"标准术语顺序"排序且没有重复元素的元素列表,就像
sort/2
一样。
如果出于某种原因你不想使用
sort/2
,可能可以使用累加器,在取交集之前检查它。
my_intersection(Xs, Ys, Zs) :-
my_intersection_1(Xs, Ys, [], Zs).
my_intersection_1([], _, Zs, Zs).
my_intersection_1([X|Xs], Ys, Zs0, Zs) :-
member(X, Ys), \+ member(X, Zs0),
my_intersection_1(Xs, Ys, [X|Zs0], Zs).
my_intersection_1([_|Xs], Ys, Zs0, Zs) :-
my_intersection_1(Xs, Ys, Zs0, Zs).
当然,结果中元素的顺序现在将被反转。如果这不是你所说的“并集”,你可以例如重写
my_intersection_1/4
的前两个从句为:
my_intersection_1([], _, _, []).
my_intersection_1([X|Xs], Ys, Zs0, [X|Zs]) :-
member(X, Ys), \+ member(X, Zs0),
my_intersection_1(Xs, Ys, [X|Zs0], Zs).