Reputation: 421
I am just learning prolog and I ran into the problem where I get the same answer twice when asking for niece and nephew. I just cannot wrap my head around it. Does anyone know what I am doing wrong? Perhaps it is something having two rules for each cousin? But it works fine when asking for brother or sister..
UPDATE: I tried out some things, and after returning to the code I wrote down here, the rule of a niece being only a female doesn't work anymore. and the nephew returns false.
So I have the code:
male( ted ).
male( john ).
male( aron ).
male( nico ).
male( gio ).
female( liza ).
female( sophie ).
female( lily ).
female( elin ).
female( daisy ).
parent_of( lily , aron ).
parent_of( john , aron ).
parent_of( john , elin ).
parent_of( lily , elin ).
parent_of( sophie , gio ).
parent_of( sophie , nico ).
parent_of( daisy , liza ).
parent_of( ted , liza ).
father_of(X,Y):- male(X),
parent_of(X,Y).
mother_of(X,Y):- female(X),
parent_of(X,Y).
sister_of( X , Y ) :- % (X,Y or Y,X) %
female(X),
father_of(F,Y),
father_of(F,X),
X \= Y.
sister_of( X , Y ) :-
female(X),
mother_of(M,Y),
mother_of(M,X),
X \= Y.
brother_of(X,Y):- %(X,Y or Y,X)%
male(X),
father_of(F,Y),
father_of(F,X),
X \= Y.
brother_of(X,Y):- male(X),
mother_of(M,Y),
mother_of(M,X),
X \= Y.
niece_of(X,Y):-
dif(X,Y),
female(X),
parent_of(W,Y),
parent_of(P,X),
brother_of(P,W).
niece_of(X,Y) :-
dif(X,Y),female(X),
parent_of(W,Y),
parent_of(P,X),
sister_of(P,W).
nephew_of(X,Y) :-
dif(X,Y),
male(X),
parent_of(W,Y),
parent_of(P,X),
brother_of(P,W).
nephew_of(X,Y):-
dif(X,Y),
male(X),
parent_of(W,Y),
parent_of(D,X),
sister_of(D,W).
The output I get is
?- niece_of(X,liza).
X = aron ;
X = aron ;
X = nico ;
X = nico ;
X = gio ;
X = gio ;
false.
?- nephew_of(X,liza).
false.
Upvotes: 2
Views: 690
Reputation: 5509
First of all, according to your database, there is no one who is anyone's niece or nephew. This can be clearly seen when you draw the graph for the relation parent_of/2
.
female(lily).
female(sophie).
female(daisy).
female(elin).
female(liza).
male(john).
male(ted).
male(aron).
male(gio).
male(nico).
parent_of(lily, aron).
parent_of(lily, elin).
parent_of(john, aron).
parent_of(john, elin).
parent_of(sophie, gio).
parent_of(sophie, nico).
parent_of(daisy, liza).
parent_of(ted, liza).
Now, consider a first version of a rule that defines the relation siblings0/2
:
siblings0(Person1, Person2) :-
dif(Person1, Person2),
parent_of(Parent, Person1),
parent_of(Parent, Person2).
Using this rule, there are two distinct ways to prove that Aron and Elin are siblings (first, because they both have the same mother; second, because they both have the same father). However, there is only one way to prove that Gio and Nico are siblings (since there is no information on who is the father of each one of them).
?- siblings0(aron, elin).
true ; % <== same mother
true ; % <== same father
false.
?- siblings0(gio, nico).
true. % <== same mother
To avoid redundancy, we can use the the ISO built-in predicate once/1:
siblings(Person1, Person2) :- dif(Person1, Person2), person(Person1), person(Person2), once( ( parent_of(Parent, Person1), parent_of(Parent, Person2) ) ). person(Person) :- ( female(Person) ; male(Person) ).
Now, we get only one answer for each query:
?- siblings(aron, elin). true. ?- siblings(gio, nico). true.
Thus, extending your database and using the predicate siblings/2
to define other relations, everything will work fine!
female(lily).
female(sophie).
female(daisy).
female(elin).
female(liza).
female(pat). % <== add
male(john).
male(ted).
male(aron).
male(gio).
male(nico).
male(coy). % <== add
parent_of(lily, aron).
parent_of(lily, elin).
parent_of(john, aron).
parent_of(john, elin).
parent_of(sophie, gio).
parent_of(sophie, nico).
parent_of(daisy, liza).
parent_of(ted, liza).
parent_of(elin, pat ). % <== add
parent_of(elin, coy). % <== add
parent_of(gio, pat). % <== add
parent_of(gio, coy). % <== add
siblings(Person1, Person2) :-
dif(Person1, Person2),
once( ( parent_of(Parent, Person1),
parent_of(Parent, Person2) ) ).
mother_of(Mother, Child):-
female(Mother),
parent_of(Mother, Child).
father_of(Father, Child):-
male(Father),
parent_of(Father, Child).
sister_of(Sister, Person) :-
dif(Sister, Person),
female(Sister),
siblings(Sister, Person).
brother_of(Brother, Person) :-
dif(Brother, Person),
male(Brother),
siblings(Brother, Person).
niece_of(Niece, Person):-
female(Niece),
parent_of(Parent, Niece),
siblings(Parent, Person).
nephew_of(Nephew, Person):-
male(Nephew),
parent_of(Parent, Nephew),
siblings(Parent, Person).
Examples:
?- niece_of(Niece, Person).
Niece = pat,
Person = aron ;
Niece = pat,
Person = nico.
?- nephew_of(Nephew, Person).
Nephew = coy,
Person = aron ;
Nephew = coy,
Person = nico.
Upvotes: 3
Reputation: 1128
First of all some simplification and extended family tree
male(ted).
male(john).
male(aron).
male(nico).
male(gio).
male(ken).
male(vladimir).
female(liza).
female(sophie).
female(lily).
female(elin).
female(daisy).
female(barbie).
parent(lily, aron).
parent(john, aron).
parent(john, elin).
parent(lily, elin).
parent(sophie, gio).
parent(sophie, nico).
parent(vladimir, gio).
parent(vladimir, nico).
parent(daisy, liza).
parent(ted, liza).
% grandfathers
parent(ken, lily).
parent(ken, daisy).
parent(ken, sophie).
parent(barbie, lily).
parent(barbie, daisy).
parent(barbie, sophie).
father(Father, Child) :-
male(Father),
parent(Father, Child).
mother(Mother, Child) :-
female(Mother),
parent(Mother, Child).
sibling(X, Y) :-
father(Father, Y),
father(Father, X),
X\=Y.
sister(Sister, Sibling) :-
female(Sister),
sibling(Sister, Sibling).
brother(Brother, Sibling) :-
male(Brother),
sibling(Brother, Sibling).
niece(Niece, ParentsSibling) :-
female(Niece),
parent(NiecesParent, Niece),
sibling(NiecesParent, ParentsSibling).
nephew(Nephew, ParentsSibling) :-
male(Nephew),
parent(NephewParent, Nephew),
sibling(NephewParent, ParentsSibling).
I've added sibling/2
predicate to remove some reused code.
Why did you have duplications on nephew?
You did use the parent predicate there when trying to define the sister of the nephew's parent, in that case, you would get each sibling twice (once because of evaluation with mother and once because of evaluating with father). You can verify that with trace\0
.
Workaround
When looking for siblings I'm checking for 2 people with the same father (check sibling/2
predicate).
If for some reason your relations would be able to have situations that human beings can exist without fathers it won't work. In that case, you would need to modify sibling/2
predicate and use parent\2
, produce all values (with findall
for example) and then return distinct values.
Upvotes: 1