2

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!

false
  • 10,264
  • 13
  • 101
  • 209
Ilya Muradyan
  • 387
  • 2
  • 13

3 Answers3

3

(\==)/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.

mat
  • 40,498
  • 3
  • 51
  • 78
2

Especially as a novice, try to abstain from using impure constructs and perserve !

How? Use !

Instead of X \== Y simply write dif(X, Y).

repeat
  • 18,496
  • 4
  • 54
  • 166
  • 1
    Thank you, it works! As I understand, using "pure" features is more clear, but sometimes less efficient, am I right? – Ilya Muradyan Nov 16 '15 at 10:14
  • 2
    @ИльяМурадьян. In a nutshell: да! What's the use of being fast but incorrect? – repeat Nov 16 '15 at 10:20
  • 1
    No use, of course. I just wanted to realize what's the purpose of non-pure features :) – Ilya Muradyan Nov 16 '15 at 10:24
  • @ИльяМурадьян. Of course, impure features are useful, too! But they need to be handled with great care, just like, say, [tag:ffi]. – repeat Nov 16 '15 at 11:41
  • 1
    I had in 80s my first introduction to Prolog, now I wonder **where** I could find a list of *impure constructs* ? – CapelliC Nov 16 '15 at 15:11
1

Prolog is a programming language based on a specific resolution method, and the problem you describe is just that: a problem (well, I would call it a bug) in your program. The order of clauses and goals is how you control your algorithm: a sequence of steps with defined effects on your representation. Then a knowledge about such effects is IMHO unavoidable, and - I think - replacing (\==)/2 by dif/2 isn't going to make your life easier, when you'll try to code something more complex. At least, in my experience, I faced additional difficulties when I had to model and debug my code.

(\==)/2 is meant to ease metaprogramming, when you need to compare variables for identity. As such, it's effectively a rather advanced feature, not needed for your program. But (maybe because it's so similar to C/C++/Java operators), it's easy to undervalue its purpose.

For your usage, (\=)/2 would serve better, but again, it requires, for a simple use, that both arguments are instantiated. This being true, depends on the whole 'inference graph' resulting from the actual calling of goals - the operational semantic. Generally, it's not simple (or even feasible, I think) to determine if a predicate is safe to call with a specific pattern. Consider this counterexample I got as a comment about a my naive assertion - append/3, a pure Prolog library predicate, being safe for all instatiation patterns:

?- append(Xs,[a],Xs).

To avoid duplicates, and listing the outcome, I would use setof/3

?- setof(R, relative(dave, R), Relatives), maplist(writeln, Relatives).
Community
  • 1
  • 1
CapelliC
  • 59,646
  • 5
  • 47
  • 90
  • Thank you for detailed response! It seems to me that I (almost) realized the difference between dif and (\==) in this particular case. As I understood, X \== Y just cuts off the wrong results, but only if it's situated in the end (if these results have been already evaluated). And if it is situated in the beginning, (\==) does nothing, because variables X and Y are not instantiated. Am I right? Can you recommend me a book/article/site describing HOW IT WORKS. I still can't understand how does Prolog do it... And thank you for your method of avoiding duplicates) – Ilya Muradyan Nov 17 '15 at 21:03
  • The point is that \== is to be used to test variables *status*, not (only) values. Explaining in few words is beyond my capability. The example posted by @mat it's the simplest code you can try to understand: the order of goals it's essential – CapelliC Nov 17 '15 at 21:54