Большинство предикатов в Прологе не write/1
вещи.Как и в императивном и функциональном программировании, обычно большое количество функций вычисляет вещи, а другие затем "сообщают" вещи (записывая данные на консоль, изменяя пользовательский интерфейс и т. Д.
Поэтому я бы предложил построить предикат find_leaf(X)
, который объединяет переменную X
с листом. Благодаря механизму обратного отслеживания Пролога, мы можем в итоге объединиться со всеми листьями.
Получение узлов из is_tree/2
Предикат
Здесь узлы - если вы не упомянули об этом - можно получить только путем анализа предиката is_tree/2
, где первый элемент является «дочерним», а второй - «родительским».Здесь мы знаем, что что-то - это отпуск, если это узел, а не родительский элемент. Поскольку нет других механизмов для определения дерева, узел (вероятно) является дочерним в некотором предикате is_tree
.
Мытаким образом, можно реализовать предикат, который находит дочерние элементы с:
find_leave(X) :-
is_tree(X, _),
\+ is_tree(_, X).
Таким образом, первый вызов is_tree(X, _)
объединит X
с дочерним элементом в дереве, гдетак как второй вызов проверяет, что нет дочернего элемента для X
.
Это затем дает:
?- find_leave(X).
X = d ;
X = e ;
X = f ;
X = g.
Получить листья из данного корня
Мы также можем передатькорень через параметр, например: find_leave(b, X)
объединит X
со всеми дочерними элементами b
.Здесь мы делаем два случая:
R
, корень, не является родителем, в этом случае R = X
(R
это отпуск);и - в противном случае, если есть дети, мы рекурсивно называем
find_leave(C, X)
с C
ребенком.Благодаря обратному отслеживанию в конечном итоге мы получим все листья.
Итак:
find_leave(R, R) :-
\+ is_tree(_, R).
find_leave(R, X) :-
is_tree(C, R),
find_leave(C, X).
Затем мы получим для разных корней разные листья:
?- find_leave(a, X).
X = d ;
X = e ;
X = f ;
X = g ;
false.
?- find_leave(b, X).
X = d ;
X = e ;
false.
?- find_leave(R, X).
R = a,
X = d ;
R = a,
X = e ;
R = a,
X = f ;
R = a,
X = g ;
R = b,
X = d ;
R = b,
X = e ;
R = c,
X = f ;
R = c,
X = g ;
false.