memberchk/2
is a commonly defined predicate that is defined in terms of member/2
like so:
memberchk(X, Xs) :-
once(member(X, Xs)).
It therefore succeeds only for the first answer of member/2
. Its full procedural meaning does not fit into a pure relation. As an example for its non-relational behavior consider
?- memberchk(b, [X,b]), X = a.
false.
?- X = a, memberchk(b, [X,b]).
X = a.
On the other hand, in many cases memberchk/2
will be called with sufficiently instantiated arguments, where it can be seen as an efficient approximation of a pure relation.
One such pure relation behind is memberd/2
(using if_/3
):
memberd(E, [X|Xs]) :-
if_(E = X, true, memberd(E, Xs) ).
Are there any other pure relations that can be approximated by memberchk/2
for sufficiently instantiated cases?
In other words: Is memberd/2
a full, declarative replacement for memberchk/2
or are there still legitimate cases where memberchk/2
cannot be replaced by memberd/2
?
memberb/2 is a typical example from constructive negation. You can turn the requirement upside down, and for example require:
Where ~ would be constructive negation. For a discussion on how constructive negation relates to if_ see for example here.
The disadvantage of fully declarative inductive definitions, for memberd/2 or somesuch is that the Prolog disjunction (;)/2 is not able to simplify constraints, and that Prolog doesn't have a forall that would also simplify constraints such as diff/2.
So that in the end when you do it correctly with the limited (;)/2 and missig forall you get in the best case complete solutions that contain a lot of redundant constraints when you look at the full solution sets that the interpreter would produce.
Here is an example in Jekejeke Prolog, it requires the Minlog extension for the predicate diff/2 to be available:
The above two answers basically say
X = a
or~(X = a)
which is in most logics the same as a single answertrue
.You would need a Prolog interpreter, that at some points works set oriented. And maybe some operators that would force a set oriented processing. But it might break traditional Prolog code. You can probably not just sneak in fully declarative definitions into code that was based on not so declarative definitions.
Bye
Here is a well-known example use of
member/2
that cannot be represented bymemberd/2
:bridge.pl
the bridge scheduling problem given by Pascal Van Hentenryck.In the setup phase
member/2
is used: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 thissetup/3
leaves open a lot of choicepoints (actually, 219). Some (like SICStus) usememberchk/2
in that situation, thereby risking non-monotonicity.Using the following pure replacement, all choicepoints are avoided.
Alternatively using
library(lambda)
:Other uses of
tmember/2
:Here is a more compact representation:
Using
library(lambda)
andcond_t/3
:The following answer does not directly relate to the original question regarding
memberchk/2
; instead, it is a follow-up to this previous answer which defined meta-predicatetmember/2
.We propose generalizing the idiom
tmember/2
like so:Building on
t_non_empty_suffix/2
and Prolog lambdas, we can definetmemberX/2
like so:The following
old_memberX/2
andold_memberdX/2
usetmemberX/2
instead oftmember/2
:Let's compare
old_member/2
toold_memberX/2
...... and
old_memberd/2
toold_memberdX/2
!OK! How about defining
old_member
/old_memberd
directly based ont_non_empty_suffix/2
?Running above queries with these predicates we get:
Alright! Same results as before.
Let's dig a bit deeper! As a show-case for
t_non_empty_suffix/2
considerduplicate_in/2
.Using
t_non_empty_suffix/2
, Prolog lambdas,(=)/3
, andmemberd_t/3
we define:Sample query: