I am working through Seven Languages in Seven Weeks, but there is something I don't understand about prolog. I have the following program (based on their wallace and grommit program):
/* teams.pl */
onTeam(a, aTeam).
onTeam(b, aTeam).
onTeam(b, superTeam).
onTeam(c, superTeam).
teamMate(X, Y) :- \+(X = Y), onTeam(X, Z), onTeam(Y, Z).
and load it like this
?- ['teams.pl'].
true.
but it doesn't give me any solutions to the following
?- teamMate(a, X).
false.
it can solve simpler stuff (which is shown in the book):
?- onTeam(b, X).
X = aTeam ;
X = superTeam.
and there are solutions:
?- teamMate(a, b).
true ;
false.
What am I missing? I have tried with both gnu prolog and swipl.
...AND THERE IS MORE...
when you move the "can't be your own teammate" restriction to then end:
/* teams.pl */
onTeam(a, aTeam).
onTeam(b, aTeam).
onTeam(b, superTeam).
onTeam(c, superTeam).
teamMate(X, Y) :- onTeam(X, Z), onTeam(Y, Z), \+(X = Y).
it gives me the solutions I would expect:
?- ['teams.pl'].
true.
?- teamMate(a, X).
X = b.
?- teamMate(b, X).
X = a ;
X = c.
What gives?
The answer by mat gives you some high-level considerations and a solution. My answer is a more about the underlying reasons, which might or might not be interesting to you.
(By the way, while learning Prolog, I asked pretty much the same question and got a very similar answer by the same user. Great.)
The proof tree
You have a question:
To get an answer from Prolog, you formulate a query:
where both X and Y can be free variables or bound.
Based on your database of predicates (facts and rules), Prolog tries to find a proof and gives you solutions. Prolog searches for a proof by doing a depth-first traversal of a proof tree.
In your first implementation,
\+ (X = Y)comes before anything else, so it at the root node of the tree, and will be evaluated before the following goals. And if eitherXorYis a free variable,X = Ymust succeed, which means that\+ (X = Y)must fail. So the query must fail.On the other hand, if either
XorYis a free variable,dif(X, Y)will succeed, but a later attempt to unify them with each other must fail. At that point, Prolog will have to look for a proof down another branch of the proof tree, if there are any left.(With the proof tree in mind, try to figure out a way of implementing
dif/2: do you think it is possible without either a) adding some kind of state to the arguments ofdif/2or b) changing the resolution strategy?)And finally, if you put
\+ (X = Y)at the very end, and take care that bothXandYare ground by the time it is evaluated, then the unification becomes more like a simple comparison, and it can fail, so that the negation can succeed.