- •У.Клоксин, к.Меллиш программирование на языке пролог Для программистов и пользователей эвм. Предисловие редакторов перевода
- •Предисловие ко второму изданию
- •Предисловие к первому изданию
- •Глава 1 введение
- •1.1. Факты
- •1.2. Вопросы
- •1.3. Переменные
- •1.4. Конъюнкции
- •1.5. Правила
- •1.6. Заключение и упражнения
- •Глава 2 более детальное описание
- •2.1. Синтаксические правила
- •2.1.1. Константы
- •2.1.2. Переменные
- •2.1.3. Структуры
- •2.2. Литеры
- •2.3. Операторы
- •2.4. Равенство и установление соответствия
- •2.5. Арифметика
- •2.6. Общая схема согласования целевых утверждений
- •2.6.1. Успешное доказательство конъюнкции целевых утверждений
- •2.6.2. Рассмотрение целевых утверждений при использовании механизма возврата
- •2.6.3. Установление соответствия
- •Глава 3. Использование структур данных
- •3.1. Структуры и деревья
- •3.2. Списки
- •3.3. Принадлежность элементов списку
- •3.4. Пример: преобразование предложений
- •3.5. Пример: упорядочение по алфавиту
- •3.6. Использование предиката присоединить и спецификация деталей
- •Глава 4. Возврат и отсечение
- •4.1. Порождение множественных решений
- •4.2. Отсечение
- •4.3. Общие случаи использования отсечения
- •4.3.1. Подтверждение правильности выбора правила
- •4.3.2. Комбинация «отсечение-fail»
- •4.4. Проблемы, связанные с использованием отсечения
- •Глава 5 ввод и вывод
- •5.1. Ввод и вывод термов
- •5.1.1. Вывод термов
- •5.1.2. Ввод термов
- •5.2. Ввод и вывод литер
- •5.2.1. Вывод литер
- •5.2.2. Ввод литер
- •5.3. Ввод предложений
- •5.4. Чтение файлов и запись в файлы
- •5.4.1. Запись в файлы
- •5.4.2. Чтение файлов
- •5.4.3. Ввод программ
- •5.5. Объявление операторов
- •Глава 6. Встроенные предикаты
- •6.1. Ввод новых утверждений
- •Списковая форма записи
- •6.2. Выполнение и невыполнение целевого утверждения
- •6.3. Классификация термов
- •6.4. Работа с утверждениями как с термами
- •6.5. Создание структур и работа с компонентами структур
- •6.6. Воздействие на процесс возврата
- •Отсечение
- •6.7. Формирование составных целевых утверждений
- •Конъюнкция целей
- •Дизъюнкция целей
- •6.8. Равенство
- •6.9. Ввод и вывод данных
- •6.10. Обработка файлов
- •6.11. Вычисление арифметических выражений
- •6.12. Сравнение чисел
- •6.13. Наблюдение за выполнением программы на Прологе
- •Глава 7. Еще несколько примеров программ
- •7.1. Словарь в виде упорядоченного дерева
- •7.2. Поиск в лабиринте
- •7.3. Ханойские башни
- •7.4. Справочник комплектующих деталей
- •7.5. Обработка списков
- •7.6. Представление и обработка множеств
- •7.7. Сортировка
- •7.8. Использование базы данных: random, генатом, найтивсе
- •Генератор случайных чисел (random)
- •Генератор имен (генатом)
- •Генератор списков структур (найтивсе)
- •7.9. Поиск по графу
- •7.10. Просеивай Двойки, Просеивай Тройки
- •7.11. Символьное дифференцирование
- •7.12. Отображение структур и преобразование деревьев
- •7.13. Применение предикатов clause и retract
- •Глава 8. Отладка пролог-программ
- •8.1. Расположение текстов программ
- •8.2. Типичные ошибки
- •8.3. Модель трассировки
- •8.4. Трассировка и контрольные точки
- •Выдача информации о цели
- •Выдача информации о предшественниках
- •Изменение уровня трассировки
- •Вмешательство в процесс согласования цели
- •Другие команды
- •Заключение
- •8.5. Фиксация ошибок
- •Глава 9. Использование грамматических правил в прологе
- •9.1. Проблема синтаксического анализа
- •9.2. Описание синтаксического анализа на языке Пролог
- •9.3. Запись грамматических правил в Прологе
- •9.4. Присоединение дополнительных аргументов
- •9.5. Введение дополнительных условий
- •9.6. Заключение
- •Глава 10. Пролог и математическая логика
- •10.1. Краткое введение в исчисление предикатов
- •10.2. Приведение формул к стандартной форме
- •Этап 1 - исключение импликаций и зквивалентностей
- •Этап 2 - перенос отрицания внутрь формулы
- •Этап 3 - сколемизация
- •Этап 4 - вынесение кванторов общности в начало формулы
- •Этап 5 - использование дистрибутивных законов для & и #
- •Этап 6 - выделение множества дизъюнктов
- •10.3. Форма записи дизъюнктов
- •10.4. Принцип резолюций и доказательство теорем
- •10.5. Хорновские дизъюнкты
- •10.6. Пролог
- •10.7. Пролог и логическое программирование
- •Глава 11. Программные проекты на прологе
- •11.1. Простые проекты
- •11.2. Более сложные проекты
- •Приложение а. Ответы к некоторым упражнениям
- •Приложение в. Программа приведения формул исчисления предикатов к стандартной форме
- •Этап 1 - исключение импликаций
- •Этап 2 - перенос отрицания внутрь формулы
- •Этап 3 - сколемизация
- •Этап 4 - вынесение кванторов общности в начало формулы
- •Этап 5 - использование дистрибутивных законов для. & и #
- •Этап 6 - выделение множества дизъюнктов
- •Печать утверждений
- •Приложение с. Различные версии языка пролог
- •Синтаксис
- •Различные ограничения
- •Возможности окружения
- •Компиляция
- •Специальные встроенные предикаты
- •Средства отладки
- •Приложение d. Пролог для эвм dec system-10
- •Пример сеанса работы
- •Синтаксис
- •Различные ограничения
- •Возможности окружения
- •Компиляция
- •Различия во встроенных предикатах
- •Дополнительные встроенные предикаты
- •Средства отладки
- •Литература
- •Приложение е. Микро-пролог
- •Пример сеанса работы
- •Синтаксис
- •Различные ограничения
- •Возможности окружения
- •Специальные встроенные предикаты
- •Средства отладки
- •Литература
- •Приложение f. Система мпролог[19]
- •Пример сеанса работы
- •Синтаксис
- •Модульность
- •Компоненты системы мПролог
- •Различные ограничения
- •Дополнительные встроенные предикаты
- •Средства отладки
- •Литература
- •Примечания
7.12. Отображение структур и преобразование деревьев
Если некоторая структура покомпонентно копируется с целью образования новой структуры, то мы говорим, что одна структура отображается в другую. Обычно при копировании каждая компонента слегка изменяется подобно тому, как в гл. 3 мы изменяли одно предложение, превращая его в другое. В том примере нам иногда нужно было скопировать какое-то слово в точности в том виде, в каком оно встретилось в исходном предложении, а иногда при копировании нам нужно было изменить слово. Для этого мы использовали следующую программу, которая отображает первый аргумент предиката преобразовать во второй его аргумент:
преобразовать([],[]).
преобразовать([А|В],[С|D]):- заменить(А,С),преобразовать(В,D).
Поскольку отображение имеет довольно широкое применение, мы можем определить предикат отобспис такой, что целевое утверждение отобспис(Р, L, M) согласуется с базой данных, применяя предикат Р к каждому элементу списка L и образуя в результате новый список М. При этом предполагается, что предикат Р имеет два аргумента: первый аргумент для передачи «входного» элемента, а второй аргумент – для измененного элемента, подлежащего включению в список М.
отобспис((_,[],[]).
отобспис((P,[X|L],[Y|M]):- Q =..[P,X,Y],call(Q),отобспис(Р,L,М).
Об этом определении следует сказать несколько слов. Во-первых, определение содержит граничное условие (первое утверждение) и общий рекурсивный случай (второе утверждение). Во втором утверждении используется оператор '=..', формирующий целевое утверждение на основе предиката (Р), входного элемента (X) и переменной (Y), которую предикат Р должен конкретизировать, чтобы образовать измененный элемент. Затем делается попытка согласовать цель Q, в результате чего Y конкретизируется, образуя голову третьего аргумента данного вызова предиката отобспис. Наконец, рекурсивный вызов отображает хвост первого аргумента в хвост второго.
Функции предиката преобразовать может выполнять предикат отобспис. Полагая, что предикат заменить определен как в гл. 3, такое использование отобспис могло бы выглядеть следующим образом:
?- отобспис(заменить,[уоu,аrе,а,computer],Z).
Z = [i, [am, not], a, computer]
Путем упрощения предиката отобспис получается предикат обрабспис, который просто обрабатывает список, применяя некоторый предикат от одного аргумента к каждому элементу списка. При этом новый список не порождается.
обрабспис(_,[]).
обрабспис(Р,[Х|L]):-Q =…[Р,Х],call(Q),обрабспис(Р,L).
Заметим, что предикат печать_строки из гл. 5 можно было бы заменить запросом вида обрабспис(put, L), где L – это строка, которую нужно напечатать.
Отображение применимо не только к спискам; оно может быть определено для структуры любого вида. Например, рассмотрим арифметическое выражение, составленное из функторов * и +, имеющих по два аргумента. Пусть мы хотим отобразить одно выражение в другое, устраняя при этом все умножения на 1. Это алгебраическое приведение могло быть определено с помощью предиката s такого, что s(Op, L, R,Ans) означает, что выражение, состоящее из операции Ор с левым аргументом L и правым аргументом R приводится к упрощенному выражению Ans. Факты, необходимые для устранения умножений на 1, могли бы выглядеть так (из-за коммутативности умножения нужны два факта):
s(*,X,1,X).
s(*,1,X,X).
Эта таблицы упрощений позволяет нам любое выражение вида 1*Х отобразить в X. Посмотрим, как можно воспользоваться этим в программе.
При приведении выражения Е с помощью такой таблицы упрощений, мы вначале должны привести левый аргумент Е, затем привести правый аргумент Е и, наконец, посмотреть, подходит ли этот приведенный результат под случаи, предусмотренные в нашей таблице. Если это так, то мы порождаем новое выражение в соответствии с указаниями таблицы. В качестве «листьев» дерева, представляющего выражение, фигурируют целые числа или атомы, поэтому для приведения листьев к ним самим в граничном условии мы должны использовать встроенный предикат atomic. Как и выше, мы можем использовать ' =..', чтобы разложить выражение Е на функтор и компоненты;
привести(Е,Е):- atomic(E), 1.
привести(Е,F):-Е =.. [Op,L,R],привести(L,Х),привести(R, Y),s(Op,X,Y,F).
Итак, предикат привести отображает выражение Е в выражение F, используя для этого факты, имеющиеся в таблице упрощений s. А что делать, если невозможны никакие упрощения? Чтобы избежать в этом случае неудачного завершения s(Op,X, Y, F), мы должны поместить в конец каждого раздела таблицы упрощений, относящегося к определенному оператору, правило-ловушку. Приведенная ниже таблица упрощений содержит правила для сложения и умножения. Кроме того, в ней выделены правила-ловушки для каждого вида операций.
s(+,X,0,X).
s(+,0,X,X).
s(+,X,Y,X + Y) /* ловушка для + */
s(*,_,0,0).
s(*,0,_,0).
s(*,1,X,X).
s(*,X,1,X).
s(*,X,Y,X*Y). /* ловушка для * */
При наличии правил-ловушек возникает вопрос о выборе способа упрощения некоторых выражений. Например, если нам дано выражение 3+0, мы можем либо использовать первый факт, либо применить правило-ловушку для +. Благодаря способу упорядочения фактов, прежде чем применить правило-ловушку Пролог всегда будет пытаться применить правила для специальных случаев. Поэтому первое решение, полученное предикатом привести, всегда будет являться действительно упрощенным выражением (если оно возможно). Однако альтернативные решения будут иметь не самый простой вид из всех возможных.
Другое упрощение, используемое при выполнении алгебраических преобразований с помощью ЭВМ, известно как свертка констант. В выражении 3*4+a константы 3 и 4 могут быть «свернуты», что дает в результате выражение 12+а.Правила свертки констант могут быть добавлены в соответствующие места приведенной выше таблицы упрощений. Правило для сложения констант выглядит следующим образом:
s(+,X,Y,Z):- integer(X), integer(Y), Z is X+Y.
Соответствующие правила для других арифметических операций имеют аналогичный вид.
В коммутативных операциях, таких как умножение и деление, указанные выше упрощения могут давать различный эффект на выражениях, которые записаны по-разному, но алгебраически эквивалентны. Например, если правило свертки констант задано для умножения, то предикат привести совершенно правильно преобразует 2*3*а в 6*а, но а*2*3 или 2*а*3 будут преобразовываться в самих себя. Чтобы понять, почему это так, подумайте над тем, как выглядят деревья, представляющие эти выражения (см. рис. 7.4).
В первом дереве самое нижнее умножение 2*3 можно свернуть, получив 6, но во втором дереве нет поддеревьев, которые было бы можно свернуть. Однако, используя коммутативность умножения, можно добавить к таблице следующее правило, которое позволит справиться с данным конкретным случаем:
s(*,X*Y,W,X*Z):- integer(Y), integer(W), Z is Y*W.
Более общая алгебраическая система может быть построена путем простого добавления дополнительных s-утверждений вместо увеличения объема программы для привести.
Рис. 7.4
