prologprolog-dif

Prolog: a person is a sibling of himself?


I'm having some trouble understanding why my code in prolog does something based on the order I put my rules in.

Here is my database:

parent(tom, bob).
parent(tom, liz).
parent(mary, bob).
parent(mary, liz).

male(tom).
male(bob).
female(mary).
female(liz).

And here are the rules:

%difference(X, Y) ==> Predicate to check if two people X and Y are not the same person.
difference(X, Y) :- \==(X, Y).
father(X, Y) :- male(X), parent(X, Y), difference(X, Y).
mother(X, Y) :- female(X), parent(X, Y), difference(X, Y).
sibling(X, Y) :-
    difference(X, Y),
    mother(M, X), mother(M, Y),
    father(F, X), father(F, Y).

The problem is that when I do this,

?- sibling(bob, X).

I get

X = bob ;
X = liz ;
false.

But when I change the ordering (I put difference(X, Y) at the last part)

sibling(X, Y) :-
    mother(M, X), mother(M, Y),
    father(F, X), father(F, Y),
    difference(X, Y).

and I call

?- sibling(bob, X).

I get

X = liz;
false.

which is what I want.

So far, I've only seen that the ordering of the rules matter when doing recursion. So I don't understand how bob is still a sibling of himself just because I put the difference check first.

Thanks for any help!


Solution

  • This is because of the way unification works. If you put difference first the values of X and Y are not yet unified to any values. Consider the trace:

     goal list: [sibling(bob, Z)]
     goal: sibling(bob, Z).
     X-> bob, Y -> Z
     goal list: [difference(bob, Y), mother(M, bob), mother(M, Y), father(F, bob), father(F, Y).]
     goal: difference(bob, Y) --SUCCESS
     goal list: [mother(M, bob), mother(M, Y), father(F, bob), father(F, Y).]
     goal: mother(M, bob)
     ...
    

    When you put the difference call last, both X and Y have been unified and difference will fail if they are the same value. Then backtracking will occur.

    Use the trace feature of your prolog environment to see what happens step by step during the execution.