Here is a well-known example use of member/2
that cannot be represented by memberd/2
: bridge.pl
the bridge scheduling problem given by Pascal Van Hentenryck.
In the setup phase member/2
is used:
setup(K,Ende,Disj):-
jobs(L),
make_vars(L,K),
member([stop,_,Ende],K),
....
So here, effectively the first element in the three-element list is used to select a particular task whereas memberd/2
uses the entire element for comparison. As a consequence this setup/3
leaves open a lot of choicepoints (actually, 219). Some (like SICStus) use memberchk/2
in that situation, thereby risking non-monotonicity.
Using the following pure replacement, all choicepoints are avoided.
member3l([N,D,A], Plan) :-
tmember(l3_t(N,D,A), Plan).
l3_t(N,D,A, X, T) :-
X = [Ni|_],
if_(N = Ni, ( X=[N,D,A], T = true ), T = false ).
tmember(P_2, [X|Xs]) :-
if_( call(P_2, X), true, tmember(P_2, Xs) ).
Alternatively using library(lambda)
:
member3li([N,Nd,Na], Plan) :-
tmember([N,Nd,Na]+X^T^
( X=[Nk|_],
if_( Nk = N, ( X=[N,Nd,Na], T = true ), T = false ) ),
Plan).
Other uses of tmember/2
:
old_member(X, Xs) :-
tmember( X+E^T^( X = E, T = true ; T = false ), Xs).
old_memberd(X, Xs) :-
tmember(=(X), Xs).
Here is a more compact representation:
member3l([N,D,A], Plan) :-
tmember({N,D,A}+[Ni,Di,Ai]^cond_t(N = Ni, [D,A] = [Di,Ai] ), Plan).
Using library(lambda)
and cond_t/3
:
cond_t(If_1, Then_0, T) :-
if_(If_1, ( Then_0, T = true ), T = false ).