prologunification

Is there a non-unifying alternative to member/2 in SWI-Prolog?


In prolog, the difference between A = B and A == B is that = tries to unify A with B, while == will only succeed if A and B are already unified.

member/2 does seem to perform unification.

Example session:

?- A = B.
A = B.

?- A == B.
false.

?- member(A, [B]).
A = B.

I have been looking but I can't find a non-unifying alternative to member/2, but not found anything. Is there something built in or do I have to invent my own thing? As I'm rather new to Prolog I don't trust myself with writing a performant version of this.

EDIT:

I came up with the following, though I don't know if the cut is correct. Without it, it seems to deliver two answers for that branch of the code (true, followed by false) though. I'd also still like to know if there is a standard library function for this.

member_eq(_, []) :-
    false.
member_eq(X, [H|_]) :-
    X == H,
    !.
member_eq(X, [_|T]) :-
    member_eq(X, T).

Solution

  • You may slightly modify builtin predicate member/2 to use ==/2 instead of unification:

    member_not_bind(X, [H|T]) :-
        member_not_bind_(T, X, H).
    
    member_not_bind_(_, X, Y):- X==Y.
    member_not_bind_([H|T], X, _) :-
        member_not_bind_(T, X, H).
    

    Sample run:

    ?- L=[a,b,c(E)], member_not_bind(A, L).
    false.
    
    ?- A=c(E),L=[a,b,c(E)], member_not_bind(A, L).
    A = c(E),
    L = [a, b, c(E)].
    

    I leave this here as it solves a related question (checking if X may unify with any item in L without actually performing the bindings)

    You can use double negation like this:

    member_not_bind(X, L):- \+(\+(member(X, L))).
    

    Sample runs:

    ?- A=c(e),L=[a,b,c(E)], member_not_bind(A, L).
    A = c(e),
    L = [a, b, c(E)].
    
    ?- A=d(E),L=[a,b,c(E)], member_not_bind(A, L).
    false.