3
votes

I've seen various implementations of family trees in Prolog, but I haven't found one that does what I would like to do, which is to define child and parent by referring to each other. I want to do this because sometimes I have a fact that someone is a child of someone, at other times I have the fact that someone is the parent of someone. From either of these kinds of facts, I'd like to be able to ask who are parents and who are children.

My attempt at coding this is :-

parent(mary, fred).
child(john, peter).
child(paul, peter).

parent(P, C).
parent(P, C) :- child(C, P).
child (C, P).
child(C, P) :- parent(P, C).

This seems to work ok except that it will continue to give me the same results duplicated over and over. Eg :-

[3]  ?- parent(peter, X).
true ;
X = john ;
X = paul ;
true ;
X = john ;
X = paul ;
true 

Is there a way I can get it to stop after it has given me the full set of results once ?

More generally, is this kind of definition a weird thing to want to do (because of the mutual recursion) ? I want to be able to have facts of either parent or child, as reported, but also to infer the "opposite" relationship from these.

Thanks !

1

1 Answers

2
votes

The issue with your program is that you are merging predicates. parent/2 and child/2 are facts, you should not name a rule like a fact that is already defined in your program.

Rename the rules and all will work. Also, the base clause in your rules should add a condition, that match the fact, something like this:

parent(mary, fred).
child(john, peter).
child(paul, peter).

isparent(P, C):- parent(P, C).
isparent(P, C):- child(C, P).

ischild(C, P):- child(C, P).
ischild(C, P) :- parent(P, C).

Now the query:

?- isparent(peter, X).
X = john
X = paul

Also, don't use the complement rule in your condition, that's not necessary and will avoid you the recursion