- •Глава 3 управление ходом выполнения программы
- •3. 1. Как выполняется запрос в прологе
- •Три семантические модели
- •Выполнение запроса
- •Правила, описывающие унификацию термов
- •Пример с программой "дядя"
- •Активация запроса
- •Унификация запроса
- •Обработка тела фразы
- •Обработка подцели "брат"
- •Обработка подцели "отец"
- •Неудача запроса и возврат назад
- •Поиск третьего ответа
- •Поиск несуществующих ответов
- •Выполнение запроса к правилу "регистрация"
- •Автоматический просмотр выполнения программы
- •3.2. Предикат "сократить" Пространство поиска запроса
- •Предикат "сократить" останавливает возврат назад
- •Влияние предиката "сократить" на составной запрос
- •Влияние предиката "сократить" на процедуру
- •Предикат "сократить" как подцель в составном запросе
- •Использование предиката "сократить" для того, чтобы сделать процедуру детерминированной
- •Применение предиката "сократить" для отбрасывания части пространства поиска
- •Ограничение сферы действия предиката "сократить"
- •Общее правило ограничения сферы действия предиката "сократить"
- •3. 3. Отрицание как неудача запроса Негативная информация
- •Предположение о замкнутости мира
- •Тогда и только тогда, когда
- •Предположение об открытости мира
- •Отрицание в явной форме
- •Пример процедуры, поведение которой соответствует предположению об открытости мира
- •3. 4. Встроенные предикаты, предназначенные для обеспечения ввода-вывода Побочные эффекты ввода-вывода
- •Пример запроса, в котором используется предикат "read"
- •3. 5. Встроенные предикаты, предназначенные для управления файлами
- •3. 6. Проверка типа терма
- •Использование предикатов "var" и "nonvar"
- •3. 7. Действия с текущей программой
- •Изменение значения факта
- •Алгоритм поиска с возрастом, в котором используется предикат "assert"
- •Процедура, которая учится у пользователя
- •Программа, которая модифицирует сама себя
- •3. 8. Компараторы
- •3. 9. Прочие встроенные предикаты
- •Программа ввода "вводполя"
- •3. 10. Операции Расширяемость синтаксиса языка Пролог
- •Инфиксная операция ",", обладающая правой ассоциативностью
- •Инфиксная операция, не обладающая свойством ассоциативности
- •Объявление операций
- •3. 11. Преобразование процедурного алгоритма в программу на языке пролог Сравнение поиска с возвратом и рекурсии
- •Цикл "пока"
- •Рекурсия
- •Поиск с возвратом
- •Применение предиката "findall"
- •Библиографические заметки
- •Упражнения
Применение предиката "findall"
Для построения списка окладов по всем фактам "служащий", в которых содержится заданный номер отдела, можно воспользоваться предикатом" findall". После того, как этот список будет построен, процедура "суммировать" сложит вместе все его элементы, что позволит получить итоговую сумму окладов.
суммировать ([], 0).
суммировать ([X | R], Итог): —
суммировать (R, Сумма),
Итог is X+ Сумма.
Запрос, предназначенный для вычисления итоговой суммы, будет иметь вид:
|? - findall (Окл, служащий (Имя, 100, Долж, Окл), Список),
суммировать (Список, Итог).
Список = [20000, 71500, 29000]
Итог = 120500
Данное решение, в котором употребляется предикат "findall", будет более общим (и будет обладать более широкой областью применения), чем решение, основанное на использовании правила "итог_окл" (см. выше).
Библиографические заметки
Существуют различные способы объяснения принципов работы решателя задач, реализованного в Прологе. Наиболее полно это изложено в работах [25] и [55]. Различные реализации языка Пролог обсуждаются в работах [14] и [105].
Понятие отрицания как неудачи запроса впервые было сформулировано в работе [17]. Предположение о замкнутости мира рассматривается в работах [89] и [78].
Во многих статьях отмечается "коварство" предиката "сократить". Среди наиболее интересных работ, предостерегающих об опасности употребления этого предиката, следует назвать доклад [81]. В работе [58] рассказывается об опасностях, связанных с использованием предикатов "assert" и "retract". Ковальски считает, что применение предиката "assert" более оправданно, чем употребление предиката "retract", поскольку добавление новых фраз во время выполнения программы в определенной степени сходно с генерированием лемм (метод доказательства в исчислении предикатов). В работах [46] и [58] сравниваются алгоритмы поиска с возвратом и рекурсивные алгоритмы. В работе [76] дается обзор "findall "-подобных предикатов.
Упражнения
1. Запустите интерпретатор языка Пролог и введите факты "путешествие/4" из разд. 1. 4. Напишите при помощи предиката "сократить" составной запрос, который будет находить только один город, в который можно добраться из Нью-Йорка на транспорте компании Амтрак, а затем будет отыскивать все города, в которые можно отправиться из найденного города транспортом данной компании.
2. Напишите обратимую версию процедуры, вычисляющей площадь прямоугольника (см. упр. 2 из гл. 2). При этом воспользуйтесь предикатами var (X) и nonvar (X). Если какие-либо два из трех аргументов этой процедуры будут конкретизированными, то процедура должна вычислять по ним значение третьего аргумента.
3. Предположим, что имеются две базы данных:
возраст (мери, 16).
возраст (брайен, 17).
возраст (кейт, 15).
возраст (сюзан, 15).
шоферские_курсы (кейт).
шоферские_курсы (мери).
шоферские_курсы (брайен).
Оцените полноту множества ответов и эффективность выполнения для каждого из приводимых ниже составных запросов. Составной запрос будет считаться эффективным, если он не тратит понапрасну время на поиск второго значения возраста для какого-либо лица.
|? - шоферские_курсы (X), возраст (X, Y), Y>=16. %А
|? - шоферские_курсы (X),!, возраст (X, Y), Y > = 16. %Б
|? - шоферские_курсы (X), возраст (X, Y),!, Y > = 16. %В
|? - шоферские_курсы (X), один_раз (возраст (X, Y)), Y > = 16. %Г
Обратитесь к приведенным выше базам данных "возраст" и "шоферские_курсы". Напишите процедуру "права", которая определяет, что человек может получить водительские права, если ему 16 лет дли более, и он прошел обучение на курсах шоферов, либо если ему 17 лет или более.
4. Придумайте несколько отношений, которые можно описать негатив но, например:
Такси служит транспортным средством для передвижения
из пункта А в пункт Б, если
А и Б - это нью-йоркские адреса, и
ни автобус, ни поезд не курсирует между А и Б.
Машина находится в нормальном состоянии, если
аварийные сигналы не включены.
Х является клиентом компании AT & Т, если
у Х есть телефон, и
Х не является клиентом ни компании MCI, ни компании Sprint.
Напишите Пролог-программу, в которой будет представлено одно из этих отношений, при этом воспользуйтесь предикатом "not".
5. Напишите с использованием предиката "repeat" составной запрос, который спрашивает у пользователя имена школьных товарищей и добавляет каждое имя в базу данных в виде факта:
школьный_товарищ (Имя).
После того, как пользователь введет слово "конец", запрос должен прекратить задавать вопросы и выдать на дисплей все только что введенные имена.
6. Выберите некоторую форму представления базы данных, в которой содержатся сведения об операциях с кредитными карточками. Каждая запись должна содержать сведения об имени лица, тратящего деньги, о типе операции и о сумме денег. Напишите процедуру, которая будет выдавать значение итоговой суммы всех операций для конкретного лица.
7. Воспользуйтесь отладочными средствами, чтобы понаблюдать за выполнением Вашей программы "советник_по_транспорту".
8. Преобразуйте базу данных "путешествие" в список структур. Напишите версию процедуры "можно_путешествовать", которая обеспечит работу с этим списком структур.
9. Напишите версию программы "группа" (см. упр. 3 из гл. 1), которая будет запрашивать у пользователя сведения о товарищах по группе, если не сможет найти ответ в базе данных "группа".
При модификации этой процедуры используйте предикаты "var (X)", "nonvar (X)" и "сократить", чтобы не было возврата назад в том случае, когда в качестве имени указывается аргумент, не являющийся переменной (т. е. конкретный человек может числиться только в одной группе). Если в качестве имени задается переменная, то возврат назад разрешается.
10. Воспользуйтесь предикатами ввода-вывода для того, чтобы сделать "дружественным" общение с пользователем одной из написанных Вами программ.
11. Определите операции"--" и "-->" и перепишите процедуру "можно_путешествовать5" из разд. 2. 2 так, чтобы она выдавала ответ в следующем виде:
путешествие (амтрак, нью_йорк, бостон, поезд).
путешествие (амтрак, бостон, портленд, поезд).
|? — можно_путешествовать5 (нью_йорк, портленд, М).
М = нью_йорк - - поезд - -> бостон - - поезд - -> портленд