prologmeta-predicatelogical-purity

Better definition of the reifying memberd_t/3


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.


Solution

  • 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.