The following story is from N. Wirth's (1976) Algorithms + Datastructures = Programs.
I married a widow (let's call her W)
who had a grown-up daughter (call her
D). My father (F), who visited us
quite often, fell in love with my
step-daughter and married her. Hence,
my father became my son-in-law and my
step-daughter became my mother. Some
months later, my wife gave birth to a
son (S1), who become the
brother-in-law of my father, as well
as my uncle. This wife of my father,
that is, my step-daughter, also had a
son (S2).
I'm attempting to model these relations in prolog so eventually I'll be able to type:
| ?- grandfather(i,i).
And I'll be given a "Yes", or a "No" on whether or not I'm my own grandpa.
Here is the code I have written so far (grandpa.pl):
aunt(X,Y):-
sibling(X,Z),
parent(Z,Y),
female(X).
brother(X,Y):-
sibling(X,Y),
male(X).
brother_in_law(X,Y):-
child(X,Z),
married(Z,W),
parent(W,Y),
not(sibling(X,Y)),
male(X).
brother_in_law(s1,f).
child(X,Y):-
parent(Y,X).
daughter(X,Y):-
parent(Y,X),
child(X,Y),
female(X).
daughter(d,w).
father(X,Y):-
parent(X,Y),
male(X).
father(f,i).
father_in_law(X,Y):-
child(X,Z),
married(Y,Z),
not(child(X,Y)),
male(X).
grandparent(X,Y):-
parent(X,Z),
parent(Z,Y).
grandmother(X,Y):-
grandparent(X,Y),
female(X).
grandfather(X,Y):-
grandparent(X,Y),
male(X).
grandchild(X,Y):-
child(X,Z),
child(Z,Y).
married(X,Y):-
wife(X,Y),
female(X).
married(X,Y):-
husband(X,Y),
male(X).
married(i,w).
married(f,d).
mother(X,Y):-
parent(X,Y),
female(X).
parent(X,Y):-
child(Y,X).
sibling(X,Y):-
parent(Z,X),
parent(Z,Y).
sister(X,Y):-
sibling(X,Y),
female(X).
son(X,Y):-
parent(Y,X),
male(X).
son(s1,w).
son(s2,d).
son_in_law(X,Y):-
child(X,Z),
not(child(X,Y)),
married(Z,Y),
male(X).
son_in_law(f,i).
step_daughter(X,Y):-
child(X,Z),
married(Z,Y),
not(child(X,Y)),
female(X).
step_daughter(d,i).
step_parent(X,Y):-
married(X,Z),
parent(Z,Y),
not(parent(X,Y)).
step_father(X,Y):-
step_parent(X,Y),
male(X).
step_mother(X,Y):-
step_parent(X,Y),
female(X).
step_mother(d,i).
uncle(X,Y):-
sibling(X,Z),
parent(Z,Y),
male(X).
uncle(s1,i).
Right now I'm having a lot of trouble with circular definitions so that I get into infinite loops when running the query: grandfather(i,i).
For example, I have:
(1 ms) yes {trace} | ?-
grandfather(i,i).
1 1 Call: grandfather(i,i) ?
2 2 Call: grandparent(i,i) ?
3 3 Call: parent(i,_103) ?
4 4 Call: child(_127,i) ?
5 5 Call: parent(i,_151) ?
6 6 Call: child(_175,i) ?
7 7 Call: parent(i,_199) ?
8 8 Call: child(_223,i) ?
9 9 Call: parent(i,_247) ?
10 10 Call: child(_271,i) ?
11 11 Call: parent(i,_295) ?
12 12 Call: child(_319,i) ?
13 13 Call: parent(i,_343) ?
14 14 Call: child(_367,i) ?
15 15 Call: parent(i,_391) ?
…
This is because child defines itself as has having a parent, and parent defines itself has having a child (as you'll see in the above predicates I posted).
Can anyone help me re-define my predicates for these relationships so that I can determine if I'm my own grandpa?
Best Solution
I removed everything that was unnecessary in your code and changed a few things and this is what I ended up with:
One would suppose that
married(X,Y) :- married(Y,X)
, but it leads to nasty circular proofs, so we will just put the husband first by convention.About parenthood, similar problem arises. We need to consider step parents as real parents, because the riddle depends on it. We know you can never be your own biological ancestor!
However,
parent(X,Y) :- parent(Z,Y), married(X,Z)
runs into the same problems, so I just madebio_parent
denote biological parenthood.Note that we have to be explicit about both parents, as there is no way to conclude biological parenthood from marriage! Also, your way of specification was problematic. You had something like:
However, from these rules Prolog could not infer
child(a,b)
, so you ended up whith sons who were not children! This occured a few times in your code. If you deriveb
froma
, always statea
as the fact! At first glance, this might seem like a shortcoming of Prolog's, but it isn't. Remember that every clause is just one way of proving a certain predicate. In the example above, you stated that every male child is a son, and alsoa
just so happens to be a son ofb
. Nowhere it is said that being a male child is the only way that someone could be a son though,a
might just be the exception.The next one is a bit wordy as our definition of
married
forces us to treat step fathers separately from step mothers. We unify them to step parents immediately though.As I said above, we need to consider step-parents as parents!
There were also some other mistakes in your code which I took out, I just show you some examples so you can learn from it.
First, here you say that female wives are married, and male husbands are married. So, male wives would be unmarried. Should be the other way round though, female married people are called wives!
Here I added the last line, as you don't usually consider yourself your own sibling:
Those last two are facts on the wrong predicate again. You basically override Prolog's deduction with them. They should be deducted, not stated as facts!
Now, try the program like this. And don't be surprised: You will not be the only one to be their own grandparent! ;-)