5
votes

TL;DR: sibling(a,X) succeeds with the answer X = a, but sibling(a,a) fails.


I have the following Prolog file:

children(a, c).
children(a, d).
children(b, c).
children(b, d).

sibling(X, Y) :-
   X \== Y, A \== B,
   children(X, A), children(X, B),
   children(Y, A), children(Y, B).

It seems clear enough to me, two person are siblings if their parents are the same. Also, a person is not their own sibling.

But when I tried to run some queries on GNU Prolog, I get some strange results:

| ?- sibling(a, b).

true ? a

true

true

yes

This is the intended behavior. a and b are siblings. There are three results, which is a bit weird, but I assume Prolog is binding A = c, B = d and A = d, B = c.

| ?- sibling(a, a).

no

I think this means a and a are not siblings.

| ?- sibling(a, X).

X = a ? a

X = b

X = a

X = b

X = a

X = b

X = a

X = b

(15 ms) yes

This is where I got stuck: It says X = a, which means sibling(a,a) is true, but sibling(a,a) failed in the previous query!

I feel that I'm not understanding what \== actually does in Prolog.

What is happening, and how do I fix this?

2
See this answer. And should you be using GNU, use that definition of dif/2.false

2 Answers

4
votes

TL;DR: Use —or iso_dif/2 (on conforming systems like )!


Good question, +1!

In fact, it's a question I have asked myself, and the answer has to do with : logical purity is a central aspect of what makes Prolog as a language so special, as it enables you to:

  • describe—not prescribe
  • write code that is relational—not just functional
  • think in terms of problems / solutions—not the individual steps of the search process itself
  • operate on a higher level—not get lost in nitty-gritty details

Unlike many other programming languages, Prolog programs have both procedural semantics (defining the execution steps and their order) and declarative semantics (allowing you to state relations that should hold and let the Prolog processor find a proper way of execution by itself).

But, beware: Prolog has some features that, when used, ruin declarative semantics. To prevent this, try to structure your application into two parts: an impure shell for dealing with side-effects (input/output) and a logically pure base which comprises pure monotonic Prolog code.

2
votes

Try moving the inequality to the end of the predicate. Maybe it gives you true because it's not instantiated already.

sibling(X,Y):- children(X, A), children(X, B),
               children(Y, A), children(Y, B),
               X \== Y, A \== B.