0

Prolog Question: Just started learning prolog and this was on one of the practice quizzes we were given.

Given:

avenger(thor).
avenger(captainAmerica).
sibling(thor,loki).
asgardian(thor).
asgardian(X) :- sibling(Y,X),asgardian(Y).
train1(X,Y) :- avenger(X),!,avenger(Y).
train2(X,Y) :- avenger(X),X\=Y,avenger(Y). 

List all answers returned by the following queries.

train2(A, captainAmerica). %returns A=thor.
train2(captainAmerica, A). %returns false.

My question is about the second query. Why wouldn't this return A=thor. ? I messed around a bit and if i change train2 to

train2(X,Y) :- avenger(X),avenger(Y),X\=Y.

when i run the second query I get

A=thor. 

A quick explanation of why the order of the rules in the query matters here would be awesome. Thanks.

false
  • 10,182
  • 12
  • 93
  • 182
jbccollins
  • 802
  • 1
  • 6
  • 19
  • See [this answer](http://stackoverflow.com/a/8523825/772868). So either use `dif/2` or [`iso_dif/2`](http://stackoverflow.com/a/20238931/772868) – false Dec 05 '14 at 15:18

2 Answers2

2

\= is a weird predicate... It says, "if the unification of the two arguments succeeds, fail; if the unification fails, succeed". So, as the unification of a free variable with an atom will always succeed, it fails.

Once the Y has been unified with thor, the unification of captainAmerica with thor fails, so the X \= Y succeeds.

Anyway, you should not use \= in this context. Instead, use dif/2. Try messing around with a predicate defined as:

train3(X, Y) :-
    dif(X, Y),
    avenger(X),
    avenger(Y).

Better than the other two in several ways. You can search SO for other questions with dif/2.

0

The \=/2 standard predicate is true when its arguments do not unify. Thus, it requires both arguments to be bound (i.e. not variables) to be meaningful. Your solution:

train2(X,Y) :- avenger(X), avenger(Y), X \= Y.

is correct as the two proceeding calls to the avenger/1 predicate ensure that both X and Y will be sufficiently instantiated before the call to the \=/2 predicate.

As Boris explained in his answer, the alternative of using the dif/2 predicate, have the virtue of making goal order in the clause above irrelevant. There's a caveat, however. The dif/2 predicate is not a standard predicate and not all Prolog implementations provide it.

Paulo Moura
  • 17,501
  • 3
  • 20
  • 32
  • Long ago there was a lively discussion involving `dif/2`: http://stackoverflow.com/questions/13757261/using-or-dif. I was left with the impression that it is a _de-facto_ standard. When it comes to differences between implementation you of course know more than most. –  Dec 05 '14 at 15:19
  • Major Prolog implementations supporting `dif/2` as a built-in predicate include B-Prolog, SWI-Prolog, and YAP. ECLiPSe and SICStus Prolog support it as a library predicate. Major Prolog implementations (currently) not supporting it include GNU Prolog and XSB. Other less popular Prolog implementations also do not support it. Thus, I would not classify it as a *de facto* standard predicate. Hopefully, that will change. – Paulo Moura Dec 05 '14 at 15:39
  • 1
    Please refer to [prolog-dif](http://stackoverflow.com/tags/prolog-dif/info) for a list of systems supporting `dif/2` directly and indirectly. And please add further systems should they become known of. Any ISO conforming system can provide [`iso_dif/2`](http://stackoverflow.com/a/20238931/772868) which is a safe approximation that does not have the logical flaws of both `(\=)/2` and `(\==)/2`. – false Dec 06 '14 at 23:02