We start with a pure implementation based on the builtin predicate member/2
:
common_member(Xs,Ys) :-
member(E,Xs),
member(E,Ys).
Sample queries:
?- common_member([1,2,3],[1]).
true
; false.
?- common_member([1,2,3],[4]).
false.
?- common_member([1,2,3],[2,3,1]).
true
; true
; true
; false.
Declaratively, above code is okay.
However, it leaves behind useless choicepoints when succeeding.
Also, we get redundant answers if there is more than one item present in both lists.
Can we improve above efficiency aspects while remaining logically pure?
Yes!
But how? By using if_/3
together with the reified test predicate memberd_t/3
!
common_memberd([X|Xs],Ys) :-
if_(memberd_t(X,Ys), true, common_memberd(Xs,Ys)).
Let s run above sample queries again, this time with common_memberd/2
:
?- common_memberd([1,2,3],[1]).
true.
?- common_memberd([1,2,3],[4]).
false.
?- common_memberd([1,2,3],[2,3,1]).
true.
Redundant answers have been eliminated and the succeeding queries do so deterministically.
Note that common_memberd/2
is pure, so we get sound answers even for quite general queries!
?- common_memberd([1,2,3],[A,B]).
A=1
; dif(A,1), B=1
; A=2 , dif(B,1)
; dif(A,1), dif(A,2), B=2
; A=3 , dif(B,1), dif(B,2)
; dif(A,1), dif(A,2), dif(A,3), B=3
; false.