Section 7 of "Indexing dif/2" discusses general reification and the following definition is given for a reified list-membership:
memberd_t(X, Es, T) :-
l_memberd_t(Es, X, T).
l_memberd_t([], _, false).
l_memberd_t([E|Es], X, T) :-
if_( X = E
, T = true
, l_memberd_t(Es, X, T) ).
It looks really a bit too complex for me to grasp. After all, the original memberd/2
did not use if_/3
. Only subsequent optimizations did. The original version is found in section 4:
memberd(X, [E|Es]) :-
( X = E
; dif(X, E),
memberd(X, Es)
).
which then gets optimized step-by-step towards a version using if_/3
.
So much for what I have tried. Is there a better way to define memberd_t/3
that does not rely on if_/3
directly and better exposes the fact that we have here two alternatives?
One clarification to what I meant to have the alternatives in an explicit manner. It should be next-to-trivial to write memberdr_t/3
based on it.
?- memberd_t(E,"abc",true).
E = a
; E = b
; E = c
; false.
?- memberdr_t(E,"abc",true). % how to write that with a trivial change
E = c
; E = b
; E = a
; false.
This question is not about producing a lower-level implementation as many of the answers have done (by using (\=)/2
, !/0
, and the like).
Quite the contrary, it focuses on providing a cleaner, high-level implementation.
Using (;)/3
:
% Version described in the paper.
memberd_t(_, [], false).
memberd_t(X, [E|Es], T) :-
call((X=E ; memberd_t(X, Es)), T).
memberdr_t(_, [], false).
memberdr_t(X, [E|Es], T) :-
call((memberdr_t(X, Es) ; X=E), T).
The alternative for memberd/2
can be obtained by using the commutativity of (;)/2
, In the same way, the alternative for memberd_t/2
can be obtained by using the commutativity of (;)/3
.