First, we rename memberd
to memberd_old
for the sake of clarity.
Then, we implement memberd_new/2
, which uses lagging and 1st argument indexing to prevent the creation of the useless choicepoint at the end of the list.
memberd_new(E,[X|Xs]) :-
memberd_new_aux(Xs,X,E).
% auxiliary predicate to enable first argument indexing
memberd_new_aux([],E,E).
memberd_new_aux([X1|Xs],X0,E) :-
if_(E=X0, true, memberd_new_aux(Xs,X1,E)).
Let's compare member/2
(SWI-Prolog builtin predicate), memberd_old/2
, and memberd_new/2
!
First, a ground query:
?- member(a,[a,a]).
true ;
true. % BAD!
?- memberd_old(a,[a,a]).
true.
?- memberd_new(a,[a,a]).
true.
Next, another ground query:
?- member(a,[a,b]).
true ; % BAD!
false.
?- memberd_old(a,[a,b]).
true.
?- memberd_new(a,[a,b]).
true.
Now, a query having multiple distinct solutions:
?- member(X,[a,b]).
X = a ;
X = b.
?- memberd_old(X,[a,b]).
X = a ;
X = b ; % BAD!
false.
?- memberd_new(X,[a,b]).
X = a ;
X = b.
Edit
The implementation of memberd_new/2
presented here is deprecated.
I recommend using the newer implementation shown in this answer.