- •Часть 1
- •1. Введение
- •2. Теоретические основы логического программирования.
- •2.1 Основные определения логики предикатов первого порядка
- •2.2 Стандартные формы представления формул исчисления предикатов.
- •3. Синтаксис языка программирования Пролог.
- •3.1. Основные элементы языка Пролог.
- •3.2.2. Вопросы.
- •3.2. Представление клауз Хорна на языке Пролог. Факты. Правила. Вопросы.
- •3.2.1. Представление фактов в Пролог—программах.
- •3.2.3. Правила.
- •3.2.4. Подстановки и примеры утверждений.
- •3.2.5. Пример Прологпрограммы.
- •4. Семантика языка программирования Пролог.
- •4.1 Декларативная и процедурная семантика программ на языке Пролог.
- •4.2. Вычислительная модель логической программы.
- •4.2.1. Унификация термов.
- •4.2.2. Общая схема согласования целевых утверждений.
- •4.2.3 Механизм поиска с возвратом.
- •5. Рекурсивное программирование на языке Пролог.
- •5.1 Рекурсивные правила.
- •5.2 Схема поиска решений в рекурсивных программах.
- •5.3. Списки и их представление на Прологе.
- •Основные определения.
- •Унификация списков.
- •Предикат list.
- •Типовые процедуры обработки списков на языке Пролог.
- •Предикат length.
- •5.4.2. Предикат member.
- •Предикат first.
- •Предикат last.
- •Предикат next.
- •Предикат append.
- •Предикат add.
- •Предикаты revers1 и revers2.
- •Предикат delete.
- •5.4.10. Предикат number_list.
- •5.4.11. Предикат sumlist.
- •5.4.12. Предикат delrepeat.
- •5.5 Множества и их представление на языке Пролог. Простые программы обработки множеств.
- •Основные определения.
- •Предикат unionset.
- •Пересечение множеств.
- •Разность множеств.
- •Определение подмножества.
- •5.5.6. Декартово произведение множеств.
- •Прологпрограммы сортировки списков.
- •Метод прямого выбора.
- •Метод вставки.
- •5.6.3. Метод перестановок.
- •6. Стандартные предикаты языка Пролог.
- •Арифметические предикаты.
- •6.2. Предикаты сравнения арифметических выражений и символьных термов.
- •6.3. Предикаты определения типов термов.
- •6.4. Примеры программ с использованием арифметических предикатов.
- •6.5. Предикаты вводавывода термов и символов.
- •6.5.1. Ввод/вывод термов.
- •6.5.2. Ввод/вывод символов.
- •6.6. Стандартные предикаты управления логическим выводом.
- •6.7. Стандартные предикаты обработки списков.
- •6.8. Стандартные предикаты обработки строк.
- •7. Система программирования Arity Prolog 5.0.
- •Описание среды программирования Arity Prolog 5.0.
- •Методические указания по лабораторным работам.
- •7.2.1. Лабораторная работа № 1. Простейшая программа на языке Пролог.
- •7.2.2. Лабораторная работа № 2. Использование арифметических операций и унификации арифметических выражений.
- •7.2.3. Лабораторная работа 3.1. Создание базы данных “Cессия” и запросов к этой базе данных на языке Пролог с использованием стандартного предиката fail.
- •Приложение 2. Варианты заданий по лабораторной работе 4.
- •Приложение 3. Варианты заданий по лабораторной работе 5.
- •Список литературы.
4.2. Вычислительная модель логической программы.
4.2.1. Унификация термов.
Основой вычислительной модели языка Пролог является алгоритм унификации. Унификация (или сопоставление) — основной шаг процесса вычисления запроса, именно в результате унификации происходит конкретизация переменных и обеспечивается продвижение к успешному завершению логического вывода запроса. Операндами операции унификации являются логические термы.
Термы унифицируются по следующим правилам:
Если термы Т1 и Т2 — константы, то они унифицируются только в том случае, когда они одинаковы. Целые и вещественные числа сопоставимы только с равными им числам. Атомы сопоставимы только с идентичными атомами. Строки сопоставимы с одинаковыми строками.
Если терм Т1—константа или составной терм, а Т2 — неконкретизированная переменная, не содержащаяся в Т1, то Т1 и Т2 унифицируются, причем в результате переменная Т2 конкретизируется значением Т1.
Если термы Т1 и Т2 — неконкретизированные переменные, то их унификация успешна всегда, причем в результате унификации эти переменные становятся сцепленными, то есть при конкретизации одной из них, другая одновременно конкретизируется тем же значением.
Если Т1 и Т2 составные термы, то Т1 и Т2 унифицируются успешно, когда они имеют одинаковые главные функторы и арности, и каждая пара соответствующих компонент составных термов успешно унифицируется.
При выполнении логического вывода скрыто от пользователя выполняется большое число операций унификации, обусловленных встроенным в Прологсистему алгоритмом логического вывода.
Однако, у программиста имеется возможность задать в качестве одной из целей явное выполнение унификации двух термов с помощью операции сопоставления ‘=’. Знак ‘\=’ является знаком отрицания сопоставления. Пусть Т1 и Т2 произвольные термы. Выражение Т1=Т2 истина, когда термы Т1 и Т2 унифицируемы (сопоставимы). Выражение Т1\=Т2 истина, когда Т1 и Т2 не сопоставимы.
Рассмотрим примеры использования операций сопоставления и отрицания сопоставления.
Пример 4.2.1.
?2+1=1+2.
no
Составные термы 2+1 и 1+2 не сопоставимы, и операция сопоставления этих термов неуспешна.
Пример 4.2.2.
?2+1\=1+2.
yes
Операция отрицания сопоставления термов 2+1 и 1+2 успешна.
Пример 4.2.3.
Операцию отрицания сопоставления можно использовать в правилах. Например, надо написать правило с заголовком sister(X,Y). Предикат sister(X,Y)истинен, если Xсестра Y.
Правило записывается следующим образом:
sister(X,Y) :parent(Z,X),parent(Z,Y),person(X,’ж’,_),X\=Y.
Если в Прологпрограмме записаны утверждения примера в пункте 3.2.5, то в ответ на вопрос, кто является сестрой Y? мы получим 3 ответа: ?sister(X,Y). X=’Элизабет’ ответ 1 Y=’Джон’>; X=’Анна’ ответ 2 Y=’Пат’>; X=’Пат’ ответ 3 Y=’Анна’>; no
Ответ 2 читается как“Анна сестра Пат”, а ответ 3 означает “Пат сестра Анны”. Это два различных ответа, с точки зрения выше приведенной программы.
4.2.2. Общая схема согласования целевых утверждений.
Самым общим случаем Прологпрограммы является программа, включающая как факты, так и правила. Рассмотрим процесс вычисления запроса на основе такой логической программы. Процесс вычисления начинается с некоторого исходного вопроса Q, который в общем случае может быть конъюнктивным, и завершается получением одного из двух результатов:
успешного согласования целей вопроса;
неуспеха (или неудачи).
В случае успешного вычисления мы получаем конкретизацию переменных, входящих в вопрос. Неудача означает невозможность вывода какой-либо цели вопросы из программы.
Допустим, что логическая программа P состоит из фактов и правил, а вопрос Q конъюнктивный и содержит цели G1,G2,…Gn. Интерпретатор языка Пролог будет вычислять ответ на вопрос согласно следующим принципам, на которых он реализован:
Цели запроса обрабатываются слева направо, G1 будет согласовываться первой, а Gn последней.
Предложения программы просматриваются интерпретатором сверху вниз.
Если цель Gi сопоставима с заголовком правила Hj, то она должна быть сопоставима с предикатами в правой части правила. Интерпретатор заменяет цель Gi на правую часть правила Hj. Это действие называется редукцией. Другими словами, Редукцией цели G с помощью программы P называется замена цели Gi на тело правила Cj, заголовок которого Hj унифицируется с целью Gi. Вычисление вопроса выполняется в виде последовательности редукций, цепочки преобразований исходного вопроса. На каждом этапе вычисления существует некоторая конъюнкция целей (или одна цель), называемая резольвентой. Цели, которые добавляются в запрос в результате редукции, называются производными целями от цели Gi и правила Cj. Если цель Gi сопоставима с заголовком правила Hj, то список целей в запросе увеличивается.
Если цель Gi сопоставима с фактом, то конкретизируются переменные этой цели, и общие переменные цели Gi и других целей, входящих в вопрос, затем осуществляется переход к сопоставлению следующей цели Gi+1 , и, таким образом, список целей, подлежащих согласованию уменьшается.
Когда мы таким образом достигнем последней цели в запросе, и она успешно будет согласована с каким-либо фактом программы, то текущая резольвента окажется пустой, и вычисление запроса будет успешным.
Процедуру Вычислить можно представить более формализовано на языке описания алгоритмов (псевдокоде) в следующем виде:
ПРОЦЕДУРА Вычислить (Прогр, СписокЦелей, ПризнакУспеха)
Входные параметры: Прогр: список предложений на языке Пролог; СписокЦелей: запрос;
Выходной параметр: ПризнакУспеха: истина, если СписокЦелей истинен; ложь, в противном случае.
Локальные переменные: Цель: предикат; ДругиеЦели: список целей; Достигнуты: истинностное значение; Конкрет: конкретизация переменных; H, H’, B1, B1’, ……Bn,Bn’: цели;
Вспомогательные функции: пустой(L): возвращает значение «истина», если L пустой список; голова(L): возвращает первый элемент списка L; хвост(L): возвращает остальные элемент списка L; конкат(L1,L2): присоединяет список L2 к концу списка L1; сопоставление(T1,T2,Сопоставимы, Конкрет): пытается унифицировать термы Т1 и Т2; если они унифицируются, то переменной Сопоставимы присваивается значение “истина”, а Конкрет представляет собой конкретизацию переменных; подстановка (Конкрет, Цели): производит подстановку переменных в Цели согласно Конкрет;
НАЧАЛО_ПРОЦЕДУРЫ ЕСЛИ пустой(СписокЦелей) ТО ПризнакУспеха=истина
ИНАЧЕ Цель:=голова(СписокЦелей);
ДругиеЦели:=хвост(СписокЦелей);
Достигнуты:=ложь;
ЦИКЛ ПОКА (Достигнуты=ложь И
“в программе есть еще предложения”)
ЕСЛИ следующее предложение в Прогр есть H:B1,B2,…Bn. ТО создать вариант этого предложения H’: B’1,B’2,…B’n. путем переименования переменных; сопоставление(Цель, H’, Сопоставимы, Конкрет);
ЕСЛИ Сопоставимы ТО НовыеЦели:= конкат([B’1,B’2,…B’n,],ДругиеЦели);
НовыеЦели:= подстановка(Конкрет,НовыеЦели); Вычислить(Прогр,НовыеЦели,Достигнуты);
КОНЕЦ_ЕСЛИ КОНЕЦ_ЕСЛИ ИНАЧЕ найден факт H;
создать вариант этого факта H’ путем переименования переменных;
сопоставление(Цель, H’, Сопоставимы, Конкрет);
ЕСЛИ Сопоставимы ТО НовыеЦели:= ДругиеЦели;
НовыеЦели:= подстановка(Конкрет,НовыеЦели); Вычислить(Прогр,НовыеЦели,Достигнуты);
КОНЕЦ_ЕСЛИ КОНЕЦ_ЦИКЛА
КОНЕЦ_ЕСЛИ ПризнакУспеха:=Достигнуты;
КОНЕЦ_ПРОЦЕДУРЫ
Рассмотрим пример вычисления запроса на основе программы, включающей и факт, и правила. Пусть программа содержит утверждения, приведенные ниже:
big(‘медведь’). %предложение 1
big(‘слон’). %предложение 2
little(‘кот’). %предложение 3
little(‘мышь’). %предложение 4
black(‘кот’). %предложение 5
grey(‘слон’). %предложение 6
grey(‘мышь’). %предложение 7
brown(‘медведь’). %предложение 8
dark(Z):black(Z). %предложение 9
dark(Z):brown(Z). %предложение 10
Для вычисления запроса “? dark(X),big(X). “ интерпретатор выполняется следующие действия:
Шаг 1. Текущая резольвента Q1 есть исходный запрос dark(X),big(X).
Шаг 2. Текущая резольвента Q2 является конъюнкцией целей dark(X),big(X). Выбираем первую цель G21dark(X) и, просматривая программу с первого предложения, находим предложение 9, сопоставимое с целью G21, является правилом
dark(Z):black(Z). переименовываем переменную Z на Х и вместо цели G21 подставляем правую часть правила 9. Получаем текущую резольвенту Q3black(X),big(X)
Шаг 3. Текущая резольвента Q3 является конъюнкцией целей black(X),big(X). Выбираем первую цель G31black(X) и, просматривая программу с первого предложения, находим предложение 5, сопоставимое с целью G31, black(‘кот’). при подстановке {X=’кот’}. Предложение 5 является фактом, поэтому список целей в резольвенте сократится, так как цель G31 удаляется , а в цель G32 при подстановке {X=’кот’} примет вид big(‘кот’). Получаем текущую резольвенту Q4: big(‘кот’).
Шаг 4 Текущая резольвента Q4 включает одну цель G41 big(‘кот’). Просматривая программу с первого предложения, не находим ни одного предложения, сопоставимого с целью G41, поэтому выполняется возврат на шаг 3.
Шаг 3. Текущая резольвента Q3 является конъюнкцией целей black(X),big(X). Выбираем первую цель G31black(X) и, просматривая программу с предложения 6 до конца программы, и не находим ни одного предложения 5, сопоставимого с целью G31, поэтому выполняется возврат на шаг 2.
Шаг 2. Текущая резольвента Q2 является конъюнкцией целей dark(X),big(X). Выбираем первую цель G21dark(X) и, просматривая программу с предложения 10, находим предложение 10, сопоставимое с целью G21, является правилом
dark(Z):brown(Z). переименовываем переменную Z на Х и вместо цели G21 подставляем правую часть правила 9. Получаем текущую резольвенту Q5 brown (X),big(X).
Шаг 5. Текущая резольвента Q5 является конъюнкцией целей brown(X),big(X). Выбираем первую цель G51 brown(X) и, просматривая программу с первого предложения, находим предложение 8, сопоставимое с целью G51, brown(‘медведь’). при подстановке {X=’медведь’}. Предложение 8 является фактом, поэтому список целей в резольвенте сократится, так как цель G51 удаляется , а в цель G52 при подстановке {X=’медведь’} примет вид big(‘медведь’). Получаем текущую резольвенту Q6: big(‘медведь’).
Шаг 6 Текущая резольвента Q6 включает одну цель G61 big(‘медведь’). Просматривая программу с первого предложения, находим предложение 1, сопоставимое с целью G61, которое является фактом, поэтому цель G61 удаляется из текущей резольвенты, и она становится пустой, Q7=.
Шаг 7. Текущая резольвента Q7 есть пустой дизъюнкт, это указывает на успешное завершение вычисления запроса Q1. Интерпретатор выдает конкретизацию переменной {X=’медведь’} как результат вычисления запроса.
Процесс вычисления запроса удобно представить в виде дерева поиска. Дерево поиска ответа на любой запрос строится следующим образом.
Корнем дерева является исходный вопрос Q.
Вершины дерева соответствуют целям (резольвентам), которые в общем случае являются конъюнктивными. В каждой выделяется одна цель.
Для каждого утверждения программы, заголовок которого унифицируется с выделенной в вершине целью имеется ребро, выходящее из этой вершины.
На ребрах дерева записываются подстановки, которые образуются в результате унификации выделенной в вершине цели и утверждения.
Лист дерева называется успешной вершиной, если существует подстановка, удовлетворяющая последнюю цель в списке целей. Лист дерева называется безуспешной вершиной, если нет в программе утверждений, которые сопоставимы с выделенной в вершине целью.
Рассмотрим пример построения дерева поиска для запроса: dark(X),big(X).
Когда выполнение программы достигает тупиковой вершины, отмеченной словом "неуспех", автоматически происходит возврат на предыдущий уровень дерева поиска, так как в Прологсистему встроен механизм возврата (backtracing). Выполнение алгоритм поиска решения можно представить как обход лабиринта, где на каждой развилке приходится выбирать новый путь. При попадании в тупик, т.е. на безуспешную вершину (лист дерева поиска), надо следовать в обратном направлении до первого перекрестка, и выбирать другой не опробованный путь, Процесс продолжается до тех пор, пока не встретится успешная вершина или будут пройдены все пути дерева поиска.
В вычислительной модели языка Пролог приняты правила просмотра целей в запросе слева направо и поиска сопоставимых правил и фактов в программе сверху вниз. Такой принцип поиска называется поиском в глубину. Рассмотрим теперь механизм поиска с возвратом.
