1

I'm trying to write an alternative definition to member/2 which will won't return repetitions of numbers (i.e. will only succeed once for each element). I've currently got this code working using the cut procedurally:

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

However, I'm aware that you can also use negation in a declarative approach to do this but I can't work out how to do it. If anyone could point me in the right direction that'd be great.

false
  • 10,264
  • 13
  • 101
  • 209
Carol
  • 65
  • 1
  • 5
  • I have one small comment on your current code: Try for example the *most general* query: `?- once_member(M, Ls).` to see that the current definition leaves something to be desired. – mat Jan 03 '18 at 20:03
  • 2
    [`memberd/2`](https://stackoverflow.com/a/21971885/772868) is probably what you are after. It's pure & efficient and avoids many redundancies. – false Jan 03 '18 at 21:30

1 Answers1

2

It is very simple using dif/2:

once_member(X, [X|_]).
once_member(X, [Y|T]) :-
    dif(X, Y),
    once_member(X, T).

1 ?- once_member(A, [1,2,3,3,4]).
A = 1 ;
A = 2 ;
A = 3 ;
A = 4 ;
false.

2 ?- X = a, once_member(X,[A,b]).
X = A, A = a ;
false.

3 ?-  once_member(X,[A,b]), X = a.
X = A, A = a ;
false.
lurker
  • 56,987
  • 9
  • 69
  • 103