Добавил:
ivanov666
Опубликованный материал нарушает ваши авторские права? Сообщите нам.
Вуз:
Предмет:
Файл:Языки логического программирования. Учебное пособие
.pdf
существования
Совокупность фактов и правил образует программу Пролога (или базу
знаний).
Запросы
Запросы - это цели выполнения программы Пролога. Запрос является
атомарным предикатом или конъюнкцией атомарных предикатов и
имеет синтаксис:
<- B1,..., Bm (m > 0),
где - атомарный предикат, а запятая, разделяющая атомы,
означает операцию конъюнкции. Обозначение переменных запроса
несущественно, и при переобозначении каждой переменной запрос не
изменяется.
Если запрос не имеет переменных, то ответом на запрос является
значение "Да" в случае, когда истинность конъюнкции предикатов
запроса следует из истинности конъюнкции фактов и правил
программы, и значение "Нет" в противном случае.
Если запрос имеет переменные, то по умолчанию подразумевается
квантор существования перед конъюнкцией предикатов запроса для
каждой переменной запроса. Если для какого-либо набора значений
переменных запроса и какого-либо соответствующего переобозначения
переменных в правилах и фактах и придания им согласованных с
запросом значений истинность конъюнкции предикатов запроса
следует из истинности конъюнкции фактов и правил, то такой набор
является ответом на запрос. Вычисления Пролога состоят в получении
всех ответов . на запрос. Однако если не существует такого
набора значений переменных запроса, который ведет к следованию
истинности запроса из истинности фактов и правил программы, то
ответом на запрос является значение "Нет". Отметим лишь, что
данное определение не является достаточно четким и мы его в
дальнейшем уточним.
Языки логического программированияВ.С. Рублев
71

Рассмотрим пример программы, которая образована из следующей
совокупности фактов
отец (иван, петр) <отец (петр, анна) <отец (яков, мария) <мать (анна, федор) <мать (елена, иван) <мать (елена, яков) <мать (софья, вера) <-
Пусть имеется запрос
<- родственники (федор, мария).
Этот запрос не имеет переменных. Но правила процедуры предок
позволяют установить, что предками федора являются анна,
петр, иван и елена, а предками марии являются яков и елена.
Поскольку федор и мария имеют общего предка елену, то правила
процедуры родственники позволяют установить истинность
запроса. Поэтому ответ на него Да.
Для запроса
<- родственники (вера, мария).
не удается установить его верность, так как ни вера не является
предком марии, ни мария не является предком веры и нет у них
общего предка. Поэтому ответ на запрос Нет.
Пусть теперь имеется запрос
<- предок (X, федор).
Этот запрос требует установить всех лиц, которые являются предками
федора. Ответы на запрос образуют список анна, петр, иван,
елена значений переменной X, каждое из которых логически
выводится из фактов и правил.
Рассмотрим другой запрос
Языки логического программированияВ.С. Рублев
72

<- предок (елена, X).
Этот запрос требует установить всех лиц, для которых елена является
предком (потомки елены ). Ответы на запрос образуют список иван,
яков, петр, мария, анна, федор.
Наконец, для запроса
<- предок (вера, X)
нет ни одного значения переменной X, при котором мы могли бы
вывести это отношение. Поэтому ответом на запрос является Нет, т. е.
вера не имеет потомков.
Рассмотренные примеры показывают, что вопросы (при помощи
переменных) можно задавать к любой части запроса. Однако мы не
определили, как происходят вычисления в Прологе, дающие эти
результаты.
Упражнения
1. Разработайте базу знаний для программных кодов с отношением
включает, если один программный код включает в себя другой код
(задать возможно меньшее число фактов для разрабатываемой
программной системы), и запрос, который проверяет, включен ли
первый код во второй код.
2. Для базы знаний первого упражнения написать запрос, который
для двух произвольных кодов проверяет, включен ди один из них в
другой.
3. Для базы знаний первого упражнения написать запрос, который
для заданного кода выдает все коды, которые его включают.
4. Для базы знаний первого упражнения написать запрос, который
для заданного кода выдает все коды, которые он включает.
Языки логического программированияВ.С. Рублев
73

Язык Пролог: вычисления и процедурная семантика
Пролога
Алгоритм вычислений программы на Прологе: порядок рассмотрения
атомов в запросе; вызов процедуры для атома; интерпретация
переменных и замена атома запроса; ветвление при невозможности
интерпретации; правило остановки вычислений; примеры вычислений
запросов для программы родства и программы соединения списков;
сходство Пролога с языками нормальных алгоритмов Маркова и
Рефалом.
Вычисления и процедурная семантика Пролога
Итак, выполнение программы Пролога заключается в интерпретации
значений переменных, при которой все правила становятся истинными.
Если такой интерпретации нет, то ответ Нет. Если правила программы
истинны при любой интерпретации, то ответ Да. В остальных случаях
ответами являются все всевозможные подстановки переменных, при
которых все правила истинны.
Каждую формулу Пролога (запрос, факт, правило) можно рассматривать
как процедуру . При этом левая часть правила - вход в процедуру , а
правая часть - тело процедуры , которая может содержать вызовы
других процедур. Атомарные предикаты запросов можно также
понимать как вызовы процедур .
Мы будем описывать алгоритм вычислений, одновременно
рассматривая и поясняя его на примере.
Пример 1. Рассмотрим запрос
<- предок (X, петр)
для программы предыдущего раздела.
1. В вычислениях каждый атом правой части запроса рассматривается
как вызов процедуры. Если в запросе несколько атомов, то эти атомы
рассматриваются по очереди, и если переменные очередного атома не
имеют ни одной интерпретации, ведущей к ответу для этой части
Языки логического программированияВ.С. Рублев
74

запроса, то и весь исходный запрос не имеет ответа для интерпретации
переменных, полученной в вычислениях предыдущих атомов. Если же
есть интерпретации для переменных атома, ведущие к ответу, то только
такие интерпретации переменных используются в частях запроса для
следующих атомов. В данном запросе 1 вызов процедуры предок.
2. При вызове процедуры мы по очереди рассматриваем формулы
(правила или факты) этой процедуры.
Шаг 1. В данном примере для процедуры предок мы берем сначала
первое правило для этой процедуры, но делаем регулярную замену
переменных:
предок (X1, Y1) <- мать (X1, Y1).
Вызов процедуры предок ( X, петр ) совпадает с заголовком этого
правила при интерпретации: X=X1, Y1= петр.
3. Производим интерпретацию переменных заголовка (правила или
левой части факта) и заменяем прежний атомарный запрос на запрос
тела процедуры, в котором произведена полученная интерпретация
переменных.
4. Если интерпретация невозможна, то необходимо перейти к
предыдущей точке выбора формулы процедуры. Если при этом нет
предыдущей точки выбора, то вычисления закончились неуспешно.
В примере получаем запрос
<- мать (X1, петр).
Шаг 2. С этим запросом поступаем аналогичным образом, но так как
процедура мать представляет собой множество фактов, то
рассматриваем лишь такие факты
мать(X2, Y2) <-,
которые допускают интерпретацию Y2 = петр. Так как таких нет, то
вычисление закончилось неудачно и нужно вернуться к предыдущей
Языки логического программированияВ.С. Рублев
75

точке алгоритма, где мы можем сделать следующий выбор. Такой точкой
является шаг 1, где мы выбирали правило процедуры предок.
Шаг 3. Выбираем следующее правило процедуры \unde предок с
заменой переменных:
предок (X1, Y1) <- отец (X1, Y1).
Вызов процедуры предок ( X, петр ) совпадает с заголовком этого
правила при интерпретации: X1=X, Y1 = петр. Заменяем исходный
запрос на тело процедуры с полученной интерпретацией переменных и
получаем новый запрос:
<- отец (X1, петр).
Шаг 4. С этим запросом поступаем аналогичным образом, но так как
процедура отец представляет собой множество фактов, то
рассматриваем лишь такие факты
отец (X2, Y2)<-,
которые допускают интерпретацию X2 = X1, Y2 = петр. Есть 1
такой факт
отец (иван, петр) <-,
который дает интерпретацию X2=иван.
5. Как только замена заголовка процедуры на тело дает пустой запрос,
который является истинным, вычисления исходного запроса (атома)
заканчиваются успешно.
Делая обратные подстановки иван = X2 = X1 = X, получаем
первый ответ X=иван.
Теперь необходимо вернуться к предыдущей точке выбора формулы.
Шаг 5. В процедуре предок выбираем следующее правило с заменой
переменных:
Языки логического программированияВ.С. Рублев
76

предок (X1, Y1) <- предок (Z1, Y1), мать (X1, Z1).
Вызов процедуры предок (X, петр) совпадает с заголовком этого
правила при интерпретации: X1=X, Y1= петр. Заменяем исходный
запрос на тело процедуры с полученной интерпретацией переменных и
получаем новый запрос:
<- предок (Z1,петр), мать (X1, Z1).
Мы получили запрос с 2 атомами и должны рассматривать их по
очереди.
Шаг 6. Рассматриваем запрос с первым атомом
<- предок (Z1,петр) В процедуре предок выбираем первое
правило (первое, потому что это новый запрос в нашем вычислении) с
заменой переменных:
предок (X1, Y1) <- мать (X1, Y1).
Вызов процедуры предок (X, петр) совпадает с заголовком этого
правила при интерпретации: Z1=X1,Y1=петр. Делая замену на тело
этой процедуры (с интерпретацией переменных), получаем запрос:
<- мать (X1, петр)
такой же, как и на шаге 2, вычисления которого закончились неудачно.
Поэтому выбираем следующее второе правило для процедуры предок:
предок (X1, Y1) <- отец (X1, Y1).
Вызов процедуры предок (X, петр) совпадает с заголовком этого
правила при интерпретации: X1=Z1,Y1=петр. Заменяем исходный
запрос на тело процедуры с полученной интерпретацией переменных и
получаем новый запрос:
<- отец (X1, петр).
Шаг 7. С этим запросом поступаем аналогичным образом, но так как
Языки логического программированияВ.С. Рублев
77

процедура отец представляет собой множество фактов, то
рассматриваем лишь такие факты
отец (X2, Y2) <-,
которые допускают интерпретацию X2=X1, Y2=петр. Есть 1 такой
факт
отец (иван, петр) <-,
который дает интерпретацию X2 = иван. Вычисления запроса для
первого атома шага 5 закончились успешно, и мы получаем
интерпретацию Z1 = иван, которую используем во втором атоме
запроса, рассматриваемом на следующем шаге.
Шаг 8. Рассматриваем второй атом запроса с интерпретацией
переменной Z1:
<- мать (X1, иван).
Так как процедура мать представляет собой множество фактов, то
рассматриваем лишь такие факты
мать(X2, Y2) <-,
которые допускают интерпретацию X2 = X1, Y2 = иван. Есть 1
такой факт
мать (елена, иван) <-,
который дает интерпретацию X2 = елена. Так как это факт, то
вычисления второго атома запроса также закончились успешно. В
результате получаем елена = X2=X1=X, и, следовательно, второй
ответ X = елена.
Теперь для завершения вычислений нужно вернуться к предыдущей
точке выбора и рассмотреть последнее правило процедуры предок:
Языки логического программированияВ.С. Рублев
78

предок (X1, Y1) <- предок (Z1, Y1), отец (X1, Z1).
Мы опять получили запрос с 2 атомами и должны рассматривать их по
очереди.
Шаг 9. Рассматриваем запрос с первым атомом
<- предок (Z1,петр).
Он аналогичен запросу, рассмотренному на шаге 6, и потому его
вычисление приводит к правилу
предок (X1, Y1) <- отец (X1, Y1).
Вызов процедуры предок (X, петр) совпадает с заголовком этого
правила при интерпретации: X1=Z1,Y1=петр. Заменяем исходный
запрос на тело процедуры с полученной интерпретацией переменных и
получаем запрос:
<- отец (X1, петр).
С этим запросом поступаем способом, аналогичным шагу 7, где
используется факт
отец (иван, петр) <-,
который дает интерпретацию X2=иван. Вычисления запроса для
первого атома шага 9 закончились успешно, и мы получаем
интерпретацию Z1=иван, которую используем во втором атоме
запроса, рассматриваемом на следующем шаге.
Шаг 10. Рассматриваем второй атом запроса с интерпретацией
переменной Z1:
<- отец (X1, иван).
Так как процедура отец представляет собой множество фактов, то
рассматриваем лишь такие факты
Языки логического программированияВ.С. Рублев
79

отец (X2, Y2)<-,
которые допускают интерпретацию Y2=иван. Таких фактов нет, эти
вычисления закончились неудачно. Поскольку мы перебрали все
формулы процедуры предок, то вычисления закончены. Окончательно
получаем множество ответов:
X={иван, елена}.
В рассмотренном примере аргументами предикатных термов запросов
являлись константные объекты и переменные. Однако если аргументы
имеют более сложную природу, например являются списками или
составными термами, то при сравнении запроса и заголовка процедуры
необходимо идентифицировать все части запроса с учетом их
структуры. Для этого обычно рассматривают дерево атома запроса и
дерево заголовка процедуры для этого атома, и, для того чтобы их
отождествить, необходимо получить одинаковую структуру обоих
деревьев. Рассмотрим следующий пример со списками.
Пример 2. Рассмотрим правило App склеивания списков (от append присоединение к списку). Оно выражается следующими фактом и
правилом:
App(nil; X; X) <App(U:X; Y; U:Z) <- App(X; Y; Z),
которые означают, что
1. результатом склеивания списка X с пустым списком является
список X ;
2. 2) если результат склеивания списков X и Y есть список Z, то
результат склеивания списков u.X и Y есть список U.Z.
Рассмотрим выполнение запроса
<- App (a:b:nil; b:nil; X),
при котором мы ожидаем получить X=a.b.b.nil.
Языки логического программированияВ.С. Рублев
80
Соседние файлы в предмете [НЕСОРТИРОВАННОЕ]
