1

I am learning to use SWI Prolog, and I am learning to use lists. A small exercise is to check if an element is in a list. Here's what I got:

member(X,[X|_]).
member(X,[_|T]):-member[X|T].

The first case goes as intended:

?- member(a,[b,a]).
true.

But the second doesn't, as some backtracking seems to appear:

?- member(a,[a,b]).
true ;
false.

How could I prevent this from happening, i.e. to get Prolog return me only true? (I don't want to ignore false.)

false
  • 10,264
  • 13
  • 101
  • 209
G. Gendre
  • 25
  • 1
  • 5
  • 1
    The first `true` means it succeed. The `false` means that when you asked it to find more solutions with `;` it found no more, so it came back `false` at that point. Normal Prolog behavior. Also, `member/2` is a standard Prolog predicate. You should name yours something else. The standard predicate has the same behavior that you show. – lurker Mar 15 '17 at 20:27

4 Answers4

6

member/2 is a standard Prolog predicate. You should name yours something else. The standard predicate has the same behavior that you show.

When you query:

?- member(a, [a,b]).
true ;
false.

Prolog finds that a matches the first element and succeeds. There's more in the list to check so it prompts you for more. Pressing ; says "yes, please, check for more". When it does, it finds no more a members so then yields false (in GNU Prolog, it would say no).

You can make it go away by either:

  • Not pressing ; but press Enter instead, OR
  • Use once/1: once(member(a, [a,b])), OR
  • You can change your predicate to include a cut in the first clause, but this is a bad idea since then it won't work in the general case: member(X, [a,b]) will only return X = a and then stop.
lurker
  • 56,987
  • 9
  • 69
  • 103
4

Using memberd/2 based on library(reif) available for SICStus|SWI, you get determinism in many cases:

?- memberd(a, [a,b]).
   true.
?- memberd(a, [a,a]).
   true.
?- memberd(a, [a,X]).
   true.
?- memberd(a, [a|Xs]).
   true.

Compare this to member/2:

?- member(a, [a,b]).
   true
;  false.              % leftover choicepoint
?- member(a, [a,a]).
   true
;  true.               % redundant solution
?- member(a, [a,X]).
  true
; X = a.               % redundant solution
?- member(a, [a|Xs]).
   true
;  Xs = [a|_A]         % redundant answer
;  Xs = [_A, a|_B]     % redundant answer
;  Xs = [_A, _B, a|_C] % redundant answer
;  ... .

And still the implementation of memberd/2 produces different answers, when necessary

?- memberd(a, [X,Y]).
   X = a
;  Y = a, dif(X, a)
;  false.

Even in this case, memberd/2 avoids the redundancy of member/2:

?- member(a, [X,Y]).
   X = a
;  Y = a.        % partially redundant

These two answers are partially redundant: X = a, Y = a is described by both!

?- member(a, [X,Y]), X = a, Y = a.
   X = Y, Y = a
;  X = Y, Y = a.    % redundant solution
false
  • 10,264
  • 13
  • 101
  • 209
0

Note that any query will unify with both clauses since member(X,[X|_]) unifies with member(X,[_|T]). You need mutually exclusive clauses. Since the prolog cut will break reversibility (as stated before), there is another option:

member(X,[X|_]).
member(X,[Y|T]):- X \== Y, member[X|T].
  • 1
    There is a good idea here, but you need `dif/2` in place of `(\==)/2`! And some brackets etc. – false Mar 16 '17 at 13:04
0

The other answer is good but maybe it is important to add that member/2 is in textbooks with this implementation exactly and because it uses pattern matchin and unification it can do more interesting things...

?- member(a(X), [a(1), b(2), c(3), a(4), b(5), a(6)]).
X = 1 ;
X = 4 ;
X = 6.

There is also memberchk/2 which is for testing for membership only. The other answer also explain how to implement.

It seems the two are on purpose not the same (why make both otherwise?)