Второй формой утверждения в логической программе являются вопросы или целевые утверждения. Для записи вопросов будем использовать следующую нотацию:
?– R1, R2, … Rn.
Здесь Ri– условия (цели), при выполнении которых целевое утверждение не отвергается. Вопрос– это средство извлечения информации из логической программы. С помощью вопроса выясняется, выполнено ли некоторое отношение (цель) или совокупность отношений между объектами (целей). Простой вопрос состоит из одной цели.
Логические следствия выводятся различными способами. Простейшее из них– совпадение: из наличия в базе данных факта «P.» следует истинность целевого утверждения «?– P.». По аналогии: из наличия «R1.», «R2.», … «Rn.» логически следует истинность «?– R1, R2, … Rn.». Возможные варианты ответов на вопрос: Yes– в случае его истинности и No, если в базе данных отсутствуют данные, подтверждающие истинность целевого утверждения[5].
Так к приведенной выше программе можно задать, например, следующие вопросы и получить на них ответы:
?– man("Петр I").
Yes
?–woman("Елизавета Петровна").
Yes
?– woman("Павел I").
No
?– man("Генрих III").
No
Обратите внимание на последний вопрос. На него был получен отрицательный ответ. И дело тут, конечно, не в склонностях последнего из Валуа[6], а в том, что в данной программе нет никакой информации об этом французском короле. Ответ No следует так и трактовать: «в базе данных нет фактов подтверждающих, что объект Генрих III обладал свойством man», и не более того. Отсюда отнюдь не следует, что он этим свойством не обладал на самом деле.
Переменные служат для обозначения неопределенных термов. С помощью вопроса, содержащего переменную, выясняется, имеется ли такое значение переменной, при котором вопрос будет логическим следствием программы. Положительный ответ на такой вопрос включает в себя все допустимые значения переменной и сообщение Yes. Понятие переменной тесно связано с понятием подстановки.
В качестве подстановок в рассматриваемой программе можно, например, рассматривать множества Ω1={X="Петр I"}, Ω2={X="Алексей Петрович"}, Ω3={X="Петр II"}, Ω4={X="Петр III", Y="Екатерина II"} и т.д. Результат применения подстановки Ω к терму A есть терм, полученный заменой каждого вхождения переменной X в терм A на t для каждой пары вида X= tÎ Ω.
Поясним сказанное на примерах. Результатом подстановки Ω1 к терму man(X) будет терм man("Петр I"), при подстановке Ω4 к pair(X, Y) будет получен терм pair("Петр III", "Екатерина II"), при подстановке Ω1 в child("Алексей Петрович", X) получим child("Алексей Петрович", "Петр I"). Попытаемся применить подстановку Ω2 к терму child("Алексей Петрович", X). Получим терм child("Алексей Петрович", "Алексей Петрович") с весьма странной интерпретацией. Здесь нет никакого противоречия, мы имеем дело именно с синтаксической конструкцией, которую определили выше как терм, а не с фактом– ничто не мешает нам задать системе вопрос:
?– child("Алексей Петрович", "Алексей Петрович")
и, естественно, получить отрицательный ответ No, т.к. не будет выполняться совпадение ни с одним из имеющихся фактов.
Положительным ответом Пролог-программы на вопрос, содержащий переменные, будут все конкретизации переменных, приводящие к обобщению и сообщение Yes. Например, к приведенной выше программе можно задать вопрос: «Чьим ребенком была Елизавета Петровна?»
?– child("Елизавета Петровна", X).
и в результате будет получен ответ:
X= "Петр I"
X= "Екатерина I"
Yes
Ответ Yes получен в соответствии с применением обобщения. Значения "Петр I" и "Екатерина I"– в результате конкретизации переменной X подстановками X= "Петр I" и X= "Екатерина I"
Более сложный вопрос: «Кто был сыном Петра I?» (иначе: «Кто был ребенком мужского пола у Петра I?») может быть представлен как конъюнкция двух целей «Кто был ребенком Петра I?»& «Был ли этот ребенок мужчиной?»:
?– child(X, "Петр I"), man(X).
X= "Алексей Петрович"
Yes
Вопросы такого рода принято называть конъюнктивными.
Обратимся к генеалогическому дереву на рисунке 1. Там указаны только два вида родственных отношений: супруги (в нашей программе pair) и ребенок (child). Тем не менее, пользуясь этой схемой, практически любой человек без особого труда сможет ответить, например, на вопрос: «Кто был отцом Павла I?». Отношение отец непосредственно на схеме не отражено. Каким же образом человек, впервые в жизни увидевший генеалогическое дерево Романовых, на основании только сведений о супружеских и родительских связях ухитряется получить эту завуалированную информацию? Очевидно, что он при этом пользуется еще чем-то, помимо непосредственно изложенных фактов. Этим «чем-то» являются общеизвестные правила, определяющие сложные родственные связи. Если человека, утверждавшего на основании рис. 1, что Петр III был отцом Павла I, спросить, почему он так думает, вероятнее всего вопрос вызовет у него недоумение: «Как это почему? На схеме ясно указано, что он ребенок Петра III, а тот хоть и плохонький был, да мужик». В терминах языка Пролог это означает, что данный вывод был сделан на основании конъюнкции фактов: child(Павел I, Петр III) & man(Петр III) (последнее уточнение необходимо для того, чтобы различить понятия мать и отец). Аналогичным образом нетрудно определить отцов и для других членов династии. В общем случае можно говорить, что некто X приходится некоторому Y отцом, если выполняются следующие условия: Y– ребенок X и X– мужчина. Мы пришли к третьему и самому важному виду утверждения в логическом программировании– правилу, позволяющему определять новые отношения в терминах существующих отношений.
Для обозначения правил используется запись вида «Q:– P1, P2, …, Pn», которая интерпретируется, как «цель Q удовлетворяется, если удовлетворяются подцели (условия) P1, P2, …, Pn, (n≥0)». Предикат Q, стоящий слева от знака «:—», называется заголовком правила, а предикаты P1, P2, …, Pn, входящие в условие, составляют тело правила. Как следует из определения, факт является частным случаем правила, при n=0.
Запишем в виде правил отношения father и mother[7] и внесем их в нашу программу: