Рассмотрим более подробно, как система ищет ответ на запрос.
Пусть наша программа пополнилась еще двумя фактами (программа 1.1):
любит (мэри, яблоки).
любит (мэри, апельсины).
любит (мэри, попкорн).
любит (бет, X):-
любит (мэри, X).
Goal: любит (мэри, X).
X — свободная (неозначенная) переменная, она не имеет значения. Она не равна 0, не равна пробелу, не равна ничему. Цель сопоставляется с первым фактом, X получает значение «яблоки». Цель доказана, Пролог выдает сообщение, что X=яблоки.
Затем X снова становится свободной переменной. Так как цель была внешней, то есть была задана после запуска программы, система будет искать все возможные решения. Поэтому цель сопоставится со вторым утверждением и X получит значение «апельсины» и будет напечатано второе решение. X снова станет свободной, цель сопоставится с третьим утверждением, будет найдено решение X=попкорн. Последнее утверждение и цель несопоставимы, поиск решений окончен.
В Прологе все переменные являются как бы локальными, значения им присваивают внутренние унификационные процедуры, и сохраняется оно только внутри данного утверждения.
Область известности (лексический диапазон) переменных — одно утверждение.
Поэтому одно и то же имя в двух разных предложениях обозначает две разных переменных.
Значение сохраняется переменной ровно до тех пор, пока:
— либо очередное сопоставление оказывается неуспешным, и вся цель несопоставимой;
— либо цель успешо вычислена.
/* Программа 1.1 «Любители морковки». Назначение:
демонстрация использованием внешней цели */
domains % описание типов объектов
% symbol — символическое имя
name, fruit = symbol
predicates
likes(name, fruit) % описание предикатов
clauses
likes(mary,apples).
likes(mary,oranges).
likes(mary,popcorn).
likes(ann,apples).
likes(beth,X):-
likes(mary,X).
likes(jonh,X):-
likes(mary,X),
likes(ann,X).
/* Конец программы */
Пример 1.2.
Генеалогическое древо имеет следующий вид (рис. 1.2)
рис.1.2
Опишем дерево с помощью отношений «родитель», «мужчина», «женщина».
родитель (том, боб). % Том — родитель Боба
мужчина (том).
женщина (пат).
Определим с помощью правил отношения «сестра», «отпрыск», «мать» (рис 1.3).
рис. 1.3
Упражнение 1.1.
По генеалогическому дереву (рис. 1.2) составить программу, включив в нее отношения «сестра», «отпрыск», «мать» (рис. 1.3).
Обратите внимание, как система отвечает на запрос
Goal: sister(X, Y). Отчего так происходит?
Опишем отношение предок(X,Z) (рис. 1.4).
рис 1.4
Для всех X и Z ,
X — предок Z, если
X — родитель Z.
Для всех X и Z ,
X — предок Z, если
(1) X — родитель Y и
существует Y , такой, что
(2) Y — предок Z.
Теперь отношение «предок» будет содержать два правила: одно для ближайших предков, другое для отдаленных.
Составим процедуру — множество утверждений об одном и том же отношении.
ancestor(X, Z):-
pearent(X, Z) .
ancestor(X, Z):-
pearent(X, Y),
ancestor(Y, Z).
Ключевым моментом в данной формулировке было использование отношения «предок» в его определении. Такое определение называется рекурсивным.
Упражнение 1.2.
В программу из упражнения 1.1 включите отношение ancestor. Задайте системе вопрос
Goal: ancestor(tom, pat)
и изобразите на диаграмме, какие шаги сделает система для достижения этой цели.