Как правило, нельзя заключать элементы в списки в предикат, если имеет смысл выводить их по отдельности, поскольку тогда становится сложнее создать «цепочку» предикатов для фильтрации или генерировать другие значения.Поэтому, как правило, лучше «излучать» отдельные элементы в промежуточных предикатах.
Родитель ребенка можно получить с помощью:
parent(Parent, Child) :-
(familija(Parent, _, Children); familija(_, Parent, Children)),
member(Child, Children).
Приятно то, что это работает разнонаправленный : мы можем запросить отдельных потомков Parent
, но мы также можем запросить, какие родители у данного Child
(или проверить, является ли Parent
родительский элемент Child
, или выполнить итерациючерез все родительско-дочерние отношения).
Например:
?- parent(P, 16).
P = 11 ;
P = 13.
Теперь мы можем сделать транзитивное замыкание над предикатом parent/2
, чтобы определить ancestor/2
:
ancestor(X, Z) :-
parent(X, Z).
ancestor(X, Z) :-
parent(X, Y),
ancestor(Y, Z).
Так что X
является предком Z
, если X
является родителем Z
, или X
является родителем Y
, а Y
является предкомиз Z
.
Итак, теперь для данного ребенка мы можем запросить всех предков:
?- ancestor(X, 16).
X = 11 ;
X = 13 ;
X = 1 ;
X = 4 ;
X = 3 ;
X = 5 ;
false.
Так что теперь единственное, что нам нужно сделать, - это обернуть их в список.Мы можем сделать это с помощью findall/3
[swi-doc] :
ancestor_list(Decendant, Ancestors) :-
findall(Ancestor, ancestor(Ancestor, Decendant), Ancestors).
Это даст нам:
?- ancestor_list(16, L).
L = [11, 13, 1, 4, 3, 5].