Search code examples
prologprolog-difdeclarative-programminglogical-purity

Order of goals(statements) in Prolog rules


I began to study Prolog recently and faced one strange problem. Here you can see a code example (I use SWI-Prolog 7.2.3) which gives a tree of relationships and my solution of 2 tasks.

/*   File:    ancestors.pl
 Author:  Dave Robertson
 Purpose: Relationships in a family tree

Suppose we have a family tree like this :

alan andrea   bruce betty      eddie elsie   fred  freda
 |     |        |     |          |     |       |     |
 |_____|        |_____|          |_____|       |_____|
    |              |                |             |
  clive        clarissa            greg         greta
   |  |__________|___|              |             |
   |__________|__|                  |_____________|
          |   |                            |
        dave doris                        henry

which is defined in Prolog by the following 3 sets of predicates:

*/

%   parent(Parent, Child).
%   Parent is the parent of Child.

parent(alan, clive).
parent(andrea, clive).
parent(bruce, clarissa).
parent(betty, clarissa).
parent(clive, dave).
parent(clarissa, dave).
parent(clive, doris).
parent(clarissa, doris).
parent(eddie, greg).
parent(elsie, greg).
parent(fred, greta).
parent(freda, greta).
parent(greg, henry).
parent(greta, henry).

%%   PROBLEM 1
%%   How do you find out if someone is the ancestor of someone else ?
ancestor(X,Y) :- parent(X,Y).
ancestor(X,Y) :- parent(X,Z), ancestor(Z,Y).

%%   PROBLEM 3
%%   How do you know if someone is related to someone else ?
relative(X,Y) :-  ancestor(X,Y).
relative(X,Y) :-  ancestor(Y,X).
relative(X,Y) :-  ancestor(Z,X), ancestor(Z,Y), X\==Y.

When I want to get the relatives of dave I do:

relative(dave,X).
X = clive ;
X = clarissa ;
X = alan ;
X = andrea ;
X = bruce ;
X = betty ;
X = doris ;
X = doris ;
X = clive ;
X = doris ;
X = clive ;
X = doris ;
X = clarissa ;
X = doris ;
X = clarissa ;
X = doris ;
false.

And then I change my definition of relative next way:

relative(X,Y) :-  ancestor(X,Y).
relative(X,Y) :-  ancestor(Y,X).
relative(X,Y) :-  X\==Y, ancestor(Z,X), ancestor(Z,Y).

I simply change the order of goals in the last statement. And now I have the following output:

relative(dave,X).

X = clive ;
X = clarissa ;
X = alan ;
X = andrea ;
X = bruce ;
X = betty ;
X = dave ;
X = doris ;
X = dave ;
X = doris ;
X = clive ;
X = dave ;
X = doris ;
X = clive ;
X = dave ;
X = doris ;
X = clarissa ;
X = dave ;
X = doris ;
X = clarissa ;
X = dave ;
X = doris ;
false.

I see dave in the output! How did this happen? I wrote that X \== Y... Can anybody give me a good explanation of this?

And one more question. How do I make my program not to write the same answers?

Thank you!


Solution

  • (\==)/2 is not a pure relation and can only be understood operationally. If you use it, exchanging the order of goals may yield declaratively wrong results:

    ?- X \== Y, X = Y.
    X = Y.
    

    Please use dif/2 instead for a pure and completely declarative way to state disequality of terms.

    ?- dif(X, Y), X = Y.
    false.
    

    See for more information.