Я думаю, что вы находитесь на правильном пути, ясно, что первый элемент списка для descendantTree/2
из X
- это X
, и за ним может (необязательно) следовать списокchildren.
Мы можем сгенерировать эти дочерние списки с помощью вызова findall/3
, где мы делаем рекурсивный вызов нашего собственного предиката, например:
descendantTree(X, [X | Ds]) :-
findall(D, (parent(X, C), descendantTree(C, D)), Ds).
Учитывая, что "childs" не существуетC
, тогда Ds
будет пустым, поэтому мы сгенерируем одноэлементный список с бездетным родителем в качестве элемента.
Если есть дочерние элементы, то мы сгенерируем потомков D
для этого дочернего элемента.и каждый из этих потомков будет добавлен в конец списка Ds
.Делая это рекурсивно, это, таким образом, сгенерирует генеалогическое древо от данного человека до всех потомков.
Например:
?- descendantTree(john, L).
L = [john, [paul, [henry, [helen]], [june]], [mary, [adam]]].
, к сожалению, мы не можем легко сгенерироватьдерево в обратном порядке:
?- descendantTree(P, L).
L = [P, [paul, [henry, [helen]], [june]], [mary, [adam]], [henry, [helen]], [june], [helen], [adam]].
здесь свободная переменная P
будет просто соответствовать чему-либо и, таким образом, будет соответствовать всем parent/2
фактам.Мы можем предотвратить это.Я оставляю это как упражнение.