0

I have a knowledge base

parent(dad, son).
parent(mom, son).
parent(dad, daughter).
parent(mom, daughter).

i have functions

mother/2
father/2
child/2

that work as expected, however when I use sibling

sibling(X,Y):-
    parent(Z,X),
    parent(Z,Y),
    not(X=Y).

the output repeats

?- sibling(X,Y).
X = son,
Y = daughter ;
X = daughter,
Y = son ;
X = son,
Y = daughter ;
X = daughter,
Y = son ;

I understand why it's repeating, my question is how do I limit it to just 1 pair non-repeating? as in

?- sibling(X,Y).
X = son,
Y = daughter ;

1 Answers1

0

You could try what lurker wrote : using X @< Y instead of not(X = Y), but then you'll get :

?- sibling(X,Y).
X = daughter ,
Y = son;
X = daughter ,
Y = son;

And then sibling(son,daughter). will return no whereas it should return true.

Or you can just hit enter after getting the first result and you will not be prompted the other results (but this depends on which environment you use as some do prompt every result without asking if you want them or not).


Edit:

What you can do to limit the results is the following :

sibling(X,Y):-
    parent(Z,X),
    parent(Z,Y),
    parent(A,X),
    parent(A,Y),
    not(X=Y),
    Z @< A.

Let me explain : in your current implementation you get 4 results because

  • son & daughter have the same mom
  • daughter & son have the same mom
  • son & daughter have the same dad
  • daughter & son have the same dad

With the previous implementation, for sibling(X,Y) to be true, X and Y need to have the same two parents, so you'll only get :

  • son & daughter have the same two parents
  • daughter & son have the same two parents

And this is to my knowledge the minimum two results you can have if you want both sibling(son,daughter) & sibling(daughter,son) to be true.

Rafalon
  • 4,450
  • 2
  • 16
  • 30
  • the problem with X@ – CarbonForm Apr 11 '17 at 15:29
  • @CarbonForm have you read my entire answer ? Ok I may have inverted daughter & son but I pointed out that `X@ – Rafalon Apr 11 '17 at 17:53
  • I think we're misunderstanding each other, I want the predicate to list true if the values are siblings, but I also want each pair to be listed only once. So that if there are three siblings, a,b, and c, it shows: X=a, Y= b; X = b, Y = c; X= a, Y = c, or some output to that effect. – CarbonForm Apr 12 '17 at 18:06
  • That is impossible to my knowledge, as if `sibling(anna,peter)` is true then `sibling(peter,anna)` is true too so each pair will always be listed at minimum twice (`X=anna Y=peter` and `X=peter Y=anna`). That's still better than what you had from the beginning : four times. – Rafalon Apr 12 '17 at 21:32