尝试这样的事情,使用内置的 member/2 和 setof\3:
set_intersection( As , Bs , Xs ) :-
set_of( X , ( member(X,As) , member(X,Bs) ) , Xs )
.
应该注意,如果列表 As 和 Bs 没有共同的元素,这将失败。另一种方法是使用findall/3 而不是set_of/3。 findall/3 如果目标不满足,将退回并清空列表而不是失败:
set_intersection( As , Bs , Xs ) :-
findall( X , ( member(X,As) , member(X,Bs) ) , Xs )
.
但是 findall/3 返回一个 bag (允许重复)而不是一个 set (不允许重复),所以如果你的两个源列表没有设置,你不会得到一个集合。
member/2 是一个内置谓词,它将其第一个参数与列表中的一个元素统一起来——相当于
member(X,[X|_).
member(X,[_|Xs) :- member(X,Xs) .
最后,正如@chac 在他的回答中指出的那样,您可以递归地遍历列表。
set_intersection( [] , _ , [] ) . % the intersection of the empty set with anything is the empty set.
set_intersection( [A|As] , Bs , [A|Xs] ) :- % if the list is non-empty,
member(A,Bs) , % - and A is a member of the 2nd set
! , % - we cut off alternatives at this point (deterministic)
set_intersection( As , Bs , Xs ) % - and recurse down on the tail of the list.
.
set_intersection( [_|As] , Bs , Xs ) :- % if the list is non-empty, and A is NOT a embmer of the 2nd set
set_intersection( As , Bs , Xs ) % we just recurse down on the tail of the list.
.
@chac 的技术会在他进行时构建结果列表,类似于:
[a|X]
[a,b|X]
[a,b,c|X]
最后的统一,空列表的特例将列表的未绑定尾部与[]统一使列表完整,所以最终的[a,b,c|X]变为
[a,b,c]
一点序幕魔法。另一种可能更容易理解的方法是使用带有累加器的工作者谓词:
%
% set_intersection/3: the public interface predicate
%
set_intersection( As , Bs , Xs ) :-
set_intersection( As , Bc , [] , T ) % we seed our accumulator with the empty list here
.
%
% set_intersection/4: the private worker bee predicate
%
set_intersection( [] , _ , T , Xs ) :- % since our accumulator is essentially a stack
reverse(T,Xs) % we need to reverse the accumulator to
. % put things in the expected sequence
set_intersection( [A|As] , Bs , T , Xs ) :-
member( A, Bs ) ,
! ,
T1 = [A|T] ,
set_intersection( As , Bs , T1 , Xs )
.
set_intersection( [_|As] , Bs , T , Xs ) :-
set_intersection( As , Bs , T , Xs )
.