Taut
Taut

Reputation: 53

Prevent unification of variables within list

I am trying to write a predicate that returns 1 if a variable X and a predicate f(X) are both elements of an input list L, and 0 if at least one of them is missing.

This is what the predicate is supposed to do:

?- f_in_list([X, f(X)], Val).
  should return Val = 1

?- f_in_list([X, f(Y), Z], Val).
  should return Val = 0, as X and Y are different variables.

I have written this simple code:

f_in_list(L, 1) :-
    member(X, L),
    member(f(X), L),
    !.
f_in_list(_, 0).

My problem is that Prolog is always trying to unify the input variables, so it returns X = f(X) and X = f(Y), respectively.
I tried to use dif(X, f(X)) in order to circumvent this issue, but even that did not work. Val will always be 1 if the list contains at least two elements.

Is there a way to convert the variables to atoms or strings, so Prolog cannot unify the variables? Or even better, is there a way to prevent the unification of variables with the same name?

Upvotes: 5

Views: 354

Answers (2)

coder
coder

Reputation: 12972

As referred by @lurker you should consider using ==/2 since it succeeds only if the two terms are already identical without further unification.

Her is my implementation:

f_in_list(L, 1) :-
    member(X, L),
    member(f(Y), L),
    X == Y ,!.

f_in_list(_, 0).

Example:

?- f_in_list([X, f(X)], Val).
Val = 1.

?- f_in_list([X, f(Y), Z], Val).
Val = 0.

Upvotes: 2

lurker
lurker

Reputation: 58274

This could be an good use of ==/2. This operator does not unify but it checks if its arguments are the same. Here is a little bit of ==/2 behavior:

2 ?- X == X
|    .
true.

3 ?- X == Y.
false.

4 ?- X = Y, Z = Y, X == Z, write('yes'), nl.
yes
X = Y, Y = Z.

5 ?- X = Y, Z = W, X == Z.
false.

6 ?-

We can use this to create a non-unifying nu_member/2 predicate:

nu_member(X, [Y|_]) :- X == Y.
nu_member(X, [_|T]) :- nu_member(X, T).

And we an use this in f_in_list/2:

f_in_list(L, 1) :-
    member(X, L),
    nu_member(f(X), L),
    !.
f_in_list(_, 0).

Which results in:

2 ?- f_in_list([X,f(X), Z], B).
B = 1.

3 ?- f_in_list([X,f(Y), Z], B).
B = 0.

4 ?- f_in_list([X,f(Y), f(Z)], B).
B = 0.

5 ?- f_in_list([X,f(Y), f(Z),Z], B).
B = 1.

Upvotes: 1

Related Questions