- •Глава 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"
- •Библиографические заметки
- •Упражнения
Использование предиката "сократить" для того, чтобы сделать процедуру детерминированной
Детерминированной называется такая процедура, про которую интерпретатору известно, что она дает более одного (позитивного) ответа. Для того чтобы превратить процедуру в детерминированную, в большинстве случаев можно воспользоваться предикатом "сократить". К примеру, если в конце каждого правила рекурсивной процедуры, выполняющей обработку списков, поставить предикат "сократить", то это позволит избежать потерь времени, затрачиваемого впустую на поиск дополнительных ответов после достижения конца списка. Предикат "сократить" информирует интерпретатор о том, что процедура является детерминированной. Приведем текст детерминированной версии процедуры "элемент", которая получила название "элемент_тест":
элемент_тест (X, [X | Остаток]): - !.
элемент_тест (X, [Y | Остаток]): -
!, элемент_тест (X, Остаток).
|?— элемент_тест (с, [a, b, c, d]).
да
Однако применение предиката "сократить" приводит к тому, что данная процедура не может выдать все элементы списка:
|? -элемент_тест (X, [a, b, c, d]).
Х=а;
нет
Применение предиката "сократить" для отбрасывания части пространства поиска
При рассмотрении программы "регистрация", представленной ранее, было обнаружено, что интерпретатор тратит понапрасну время в попытке найти более чем одно значение возраста у одного и того же лица. Существуют два подхода к этой проблеме. Во-первых, ясно, что часть пространства поиска запроса к программе "регистрация" не несет полезной информации. Эту часть пространства можно отбросить без какого-либо ущерба для способности программы выдавать все правильные ответы. Во-вторых, нужно сделать так, чтобы отношение "возраст" регулировалось ограничением, обеспечивающим целостность отношения, вида многие-к-одному, а не принимаемым по умолчанию ограничением многие-к-многим. Возникает вопрос: как можно использовать предикат "сократить" при создании новой версии процедуры "регистрация", в которой выдавались бы все те же ответы, что и в исходной версии, а бесполезные траты времени на поиск нескольких значений возраста были бы устранены? В связи с этим возникает и другой вопрос: каким образом можно употребить предикат "сократить" для того, чтобы создать версию отношения "возраст", регулируемую ограничением, обеспечивающим целостность, вида многие-к-одному?
Остановка после выдачи одного ответа
Начнем с более простой задачи — написать запрос к базе данных "возраст", при котором будет выдаваться только один ответ. К какому решению мы бы ни пришли, оно может оказаться полезным при составлении будущей версии процедуры "регистрация".
Наиболее очевидным способом составления запроса к базе. данных "возраст", при котором будет выдаваться только один ответ, будет написание составного запроса, второй подцелью которого является предикат "сократить". Если первым аргументом предиката "возраст" будет константа (имя), а вторым - переменная (возраст), то запрос будет работать нормально:
возраст (брайен, 18).
возраст (майк, 17).
возраст (став, 18).
|? - возраст (брайен, Y),!.
Y=18;
нет
Заметьте, что при данном запросе интерпретатор не будет искать значение еще одного возраста Брайена.
Однако, если первым аргументом запроса "возраст" будет переменная, а вторым — константа, то при описанном подходе интерпретатор не найдет все правильные ответы на запрос:
|? -возраст (X, 18),!.
Х= брайен;
нет
В базе данных содержатся сведения более чем об одном восемнадцатилетнем мужчине, но из-за употребления предиката "сократить" этот запрос выдаст сведения только о первом из представленных мужчин. Поэтому множество ответов данной программы будет неполным.
Предикат "сократить " как подцель правила "регистрация "
Посмотрим, что получится, если составной запрос подобного вида (т. е. подцель "возраст" плюс предикат "сократить") будет записан в теле правила "регистрация".
регистрация2 (X):—
мужчина (X), возраст (X, Y),!, Y= 18.
Запрос к правилу "регистрация2" будет работать правильно, если его аргументом является константа:
|? - регистрация2 (бранен).
да
|? -регистрация2 (майк).
нет
Дело будет обстоять не так хорошо, если аргументом запроса является переменная:
|? - регистрация2 (X).
Х= брайен ;
нет
Этот запрос не выдает еще один ответ, «X = стив», поэтому опять множество ответов программы будет неполным.
