Many systems provide a pure and efficient implementation of member/2
. In particular, no choice point is left open for:
?- member(b,[a,b]). true.
whereas, a naive implementation of member/2
produces rather:
?- member(b,[a,b]). true ; false.
which is certainly correct from a declarative viewpoint, but less efficient.
On the other hand, there are some technical problems with member/2
. It permits redundant solutions, like in:
?- member(a,[a,a]). true ; true.
memberd/2
solves this problem using if_/3
and (=)/3
.
memberd(E, [X|Xs]) :- if_(E = X, true, memberd(E, Xs)). ?- memberd(a,[a,a]). true.
Unfortunately, this definition leaves choice points open again - producing ; false
("leftover choicepoints") in situations where member does not:
?- memberd(X,[a,b]). X = a ; X = b ; false. % BAD - to be avoided! ?- member(X,[a,b]). X = a ; X = b.
So my question: Is there a definition of memberd/2
that avoids the choice point as this one above?
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.
The implementation of memberd_new/2
presented here is deprecated.
I recommend using the newer implementation shown in this answer.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With