Prolog and ancestor relationship

2020-02-12 17:15发布

I have to write a small prolog program which checks if a given person is a ancestor of a second one. These are the facts and rules:

mother(tim, anna).
mother(anna, fanny).
mother(daniel, fanny).
mother(celine, gertrude).
father(tim, bernd).
father(anna, ephraim).
father(daniel, ephraim).
father(celine, daniel).

parent(X,Y) :- mother(X,Y).
parent(X,Y) :- father(X,Y).

The test if a person is an ancestor of another person is easy:

ancestor(X, Y) :- parent(X, Y).
ancestor(X, Y) :- parent(X, Z), ancestor(Z, Y).

But now I have to write a method ancestor(X,Y,Z) which also prints out the relationship between two persons. It should look like this

?- ancestor(ephraim, tim, X).
false.
?- ancestor(tim, ephraim, X).
X = father(mother(tim)).

And that is the problem: I have no clue how do to this.

标签: prolog
3条回答
Anthone
2楼-- · 2020-02-12 17:58

You can use an accumulator to adapt @Scott Hunter's solution :

mother(anna, fanny).
mother(daniel, fanny).
mother(celine, gertrude).
father(tim, bernd).
father(anna, ephraim).
father(daniel, ephraim).
father(celine, daniel).

ancestor(X, Y, Z) :- ancestor(X, Y, X, Z).
ancestor(X, Y, Acc, father(Acc)) :- father(X, Y).
ancestor(X, Y, Acc, mother(Acc)) :- mother(X, Y).
ancestor(X, Y, Acc, Result) :-
    father(X, Z),
    ancestor(Z, Y, father(Acc), Result).
ancestor(X, Y, Acc, Result) :-
    mother(X, Z),
    ancestor(Z, Y, mother(Acc), Result).

edit : as Scott Hunter showed in his edit, there's no need for an explicit accumulator here, since we can left the inner part of the term unbound easily at each iteration. His solution is therefore better !

查看更多
神经病院院长
3楼-- · 2020-02-12 17:59

Simply add a term which tracts what kind of parent is used at each step (edited to get result in proper order):

ancestor(X,Y,father(X)) :- father(X,Y).
ancestor(X,Y,mother(X)) :- mother(X,Y).
ancestor(X,Y,father(Z2)) :- father(Z,Y), ancestor(X,Z,Z2).
ancestor(X,Y,mother(Z2)) :- mother(Z,Y), ancestor(X,Z,Z2).
查看更多
4楼-- · 2020-02-12 18:10

A term manipulation alternative to the accumulator tecnique by @Mog:

parent(X, Y, mother(X)) :- mother(X, Y).
parent(X, Y, father(X)) :- father(X, Y).

ancestor(X, Y, R) :-
    parent(X, Y, R).
ancestor(X, Y, R) :-
    parent(X, Z, P),
    ancestor(Z, Y, A),
    eldest(A, P, R).

eldest(A, P, R) :-
    A =.. [Af, Aa],
    (   atom(Aa)
    ->  T = P
    ;   eldest(Aa, P, T)
    ),
    R =.. [Af, T].

To test, I made tim a father: father(ugo, tim).

?- ancestor(tim, ephraim, X).
X = father(mother(tim)) .

?- ancestor(ugo, ephraim, X).
X = father(mother(father(ugo))) .
查看更多
登录 后发表回答