- •Курс лекций по дисциплине «Логическое программирование» Специальность 220400 «по вт и ас» Факультет ирт Кафедра вМиК Курс 5 (веч) Основные конструкции логической программы
- •Введение в программирование на языке Пролог
- •Применение рекуpсии
- •Работа со списками
- •Соpтиpовка списков
- •Динамические базы данных
- •Принцип резолюций
- •Полное пространство вычислений.
- •Разрешимость логических программ. Спецификация программ
- •Правильность исполнения логических программ
- •Описание процесса верификации логических программ
- •Синтез логических программ
- •Логическое программирование и базы данных
Введение в программирование на языке Пролог
Для изучения Пролога издана литература:
1. Ц.Ин,Д.Соломон. Использование Турбо-Пролога. "Мир".М.1993.
2. И.Братко. Программирование на языке Пролог для искусственного интеллекта. Мир".М.1990.
3. Дж.Стобо. Язык программирования Пролог. "Радио и связь". М.1993.
4. У.Клоксин, К.Меллиш. Программирование на языке Пролог. "Мир".1987.
5. Дж.Малпас. Реляционный язык Пролог и его применение. "Наука".М.1990.
6. А.Янсон. Турбо-Пролог в сжатом изложении. "Мир". М. 1991
7. Язык Пролог в пятом поколении ЭВМ. Сб.статей. "Мир".М.1988
В отличие от алгоритмических, процедурных языков программирования, Пролог относится к логическим, декларативным языкам. При использовании языков первой группы программист задает машине способ решения поставленной задачи, называемый алгоритмом. Программы на Прологе содержат только описания (декларации) отношений между объектами, которые необходимы для решения задачи. Способ решения задачи выбирает сама машина. Поэтому программы на Прологе бывают понятнее и много короче, чем на алгоритмических языках программирования.
Основой Пролога является логическая система предикатов первого порядка.
Программа на Прологе состоит из фактов, правил, вопросов и (в Турбо) описания типов используемых в ней предикатов.
Программа.
Domains % Это название раздела типов данных
name = symbol
Predicates % Это название раздела с описанием предикатов.
likes(name, name)
Сlauses % Это название раздела с фактами и правилами.
likes("Зина", "мороженое").
likes("Зина", "чтение").
likes("Нина", "мороженое").
likes("Нина", "чтение").
likes("Саша", Х) :- likes("Зина", Х), likes("Нина", Х).
Goal % Это название раздела с вопросом.
likes("Саша",Y), write(Y), nl.
Дерево родственных отношений:
Predicates
Родитель(name, name).
Run.
Run(name, name).
Goal Run.
Clauses
Родитель(пам, боб).
Родитель(том, боб).
Родитель(том, лиз).
Родитель(боб, энн).
Родитель(боб, пат).
Родитель(пат, джим).
Run :- Родитель(боб, пат). -> Yes.
Run :- Родитель(лиз, пат). -> No.
Вопрос: «Кто является родителем родителя Джима»
Run(X,Y) :- Родитель(Y, джим), Родитель(X, Y) -> X=боб, Н=пат.
Цели бывают внутренние и внешние. Для внутренней цели Пролог находит только первое решение с полученными значениями переменных. Для внешней – все достижимые цели.
Для того чтобы иметь возможность выбирать из программы данные, удовлетворяющие некоторым условиям, необходимо иметь средства управления откатом. В Прологе для этой цели используется предикат cut (отсечение), который в программе обозначается символом восклицательного знака !. Этот предикат, вычисление которого всегда завершается успешно, заставляет внутренние программы сопоставления «забыть» все указатели отката, установленные во время попыток вычислить предыдущие подцели. Так например, вычисление правила pr:-a,b,!,c., в котором имеется предикат отсечения, представьте таким образом: при вычислении подправилa а, затем b осуществляется последовательный поиск решений с откатами до тех пор, пока не будут удовлетворены эти подцели; далее произойдет успешное завершение предиката отсечения !; затем начнется вычисление подцели с, но здесь откаты возможны только при поиске решений для с и благодаря отсечению становятся невозможными откаты для нового поиска альтернативных решений для подцелей a,b.
Run :- Родитель(X, Y).
Goal: Run.
% будет одно – первое согласование
Run(X, Y) :- Родитель(X, Y).
Goal: Run(X,Y).
% будет 6 согласований
Run(X, Y) :- Родитель(X, Y), !.
Goal: Run(X,Y).
% будет 1 согласование
Расширим нашу программу с помощью новых правил: добавим информацию о том, каков пол людей, участвующих в отношении Родитель.
Женщина(пам).
Мужчина(том).
Мужчина(боб).
Женщина(лиз).
Женщина(пат).
Женщина(энн).
Мужчина(джим).
Мы ввели 2 новых отношения: мужчина и женщина. Это унарные или одноместные отношения. Эту же информацию можно было выразить с помощью бинарного отношения пол:
Пол(пам, женский).
Пол(том, мужской).
…
Женщина(X) :- Пол(X, женский).
Мужчина(X) :- Пол(X, мужской).
ИмеетРебенка(X) :- Родитель(X, _) % _ = анонимная переменная
Отпрыск(Y, X) :- Родитель(X, Y).
Мать(X, Y) :- Родитель(X, Y), Женщина(X).
Сестра(X, Y) :- Родитель(Z, X), Родитель(Z, Y), Женщина(X).
Goal: Сестра(энн, пат).
Ответ: yes.
Goal: Сестра(X, пат).
X=энн, Х=пат. % упущение пат = сестра себе самой
Поэтому необходимо введение предиката Различны(X, Y):
Различны(X, Х) :- !, fail.
Различны(X, Y).
Тогда
Сестра(X, Y) :- Родитель(Z, X), Родитель(Z, Y), Женщина(X), Различны(X, Y).
Алгоритма логического вывода в программе нет. Этот алгоритм встроен в саму систему Пролога. Поиск решения в данной задаче осуществляется так. В разделе Сlauses методом перебора сверху вниз производится поиск факта или головы правила с предикатом того же типа, что и в цели. При совпадении имен предикатов, количества и типов аргументов, производится их сопоставление, называемое также унификацией.
Если аргумент в запросе является константой, а в факте тоже константа с тем же значением, то сопоставление заканчивается успешно. При сопоставлении переменной с константой, эта переменная получает значение константы. При сопоставлении переменной с переменной, у которой другое имя, первая переменная получает ее имя. Далее производится сопоставление следующего аргумента и т.д.
Если произошло успешное сопоставление всех аргументов, то соответствующий предикат в цели получает значение истинности, а его переменные получают значения соответствующих констант и становятся связанными переменными. Если ни одно из указанных условий унификации, хотя бы для одного из аргументов, не выполнено, то сопоставления не произошло и предикат в цели получает значение ложь. В этом случае продолжается поиск и выбор для сопоставления следующих фактов.
А как определить предикат Предок(X, Y)?
Предок(X, Y) :- Родитель(X, Y).
Предок(X, Y) :- Родитель(X, Z), Родитель(Z, Y).
…
Но корректнее – с применением рекурсии:
Предок(X, Y) :- Родитель(X, Y).
Предок(X, Y) :- Родитель(X, Z), Предок(Z, Y).
Рассмотрим все шаги достижения цели Goal: Предок(том, пат) в форме дерева:
max(C1,C2,C1):-C1>C2,!.
max(C1,C2,C2).
Метод повтopа по выбоpу пpогpаммиста
Вид правила повтора, определяемого программистом:
repeat. /* повторить */
repeat:-repeat.
Когда при выполнении программы в одном из ее правил встретится подцель с предикатом repeat и выполнение следующих подцелей будет успешным, произойдет возвращение к подцели repeat для поиска других возможных решений, а ее обращение к правилу repeat создаст условия для отката и повторного выполнения следующих подцелей.
Рассмотрим работу правила повтора на примере с программой, которая просит пользователя вводить названия животных и выдает их на экран, пока пользователь не введет слово stop.
domains
name = symbol
predicates
repeat
write_message
do_echo
check(name)
goal write_message, do_echo.
clauses
repeat.
repeat :- repeat.
write_message :- nl, write("Вводите названия животных."), nl, write("Я повторю их."), nl,
write("Чтобы остановиться, введите stop."),nl,nl.
do-echo :- repeat, readln(N), /* ввод значения симв.переменной */
write(N),nl, check(N),!.
check(stop) :- nl, write(" Конец!").
check(_) :- fail.
Правило repeat записано первым в разделе утверждений программы.
Второе правило выводит информацию для пользователя.
Третье правило является правилом повтора (выполнить эхо), определенным программистом. Утверждение repeat в нем вызывает повторное выполнение всех следующих за ним компонент.
Последнее подправило check(N) имеет два возможных значения. Одно из них завершает работу, другое всегда дает неудачу для возвращения к подправилу repeat для повторения ввода.
Встроенный предикат readln c одним аргументом, который должен быть именем переменной, обеспечивает приостанов программы в ожидании ввода символьного значения. Это значение получает переменная, после чего работа программы продолжается.
