
- •Предисловие
- •Глава 1 Введение в Пролог
- •Глава 2 Синтаксис и унификация
- •2.1. Синтаксис термы
- •Константы
- •Переменные
- •Область действия переменных
- •Сложные термы, или структуры
- •Синтаксис операторов
- •Синтаксис списков
- •Синтаксис строк
- •Утверждения
- •Запросы
- •Ввод программ
- •2.2 Унификация
- •Глава 3 Арифметические выражения
- •3.1. Введение
- •3.2. Арифметические выражения
- •3.3. Арифметические операторы
- •3.4. Вычисление арифметических выражений
- •3.5. Сравнение результатов арифметических выражений
- •Глава 4 Рекурсия
- •4.1. Стратегия «разделяй и властвуй»
- •Пример 4.1.1
- •Фаза разбиения
- •Фаза решения задачи
- •4.2. Восходящая стратегия
- •4.3. Рекурсия и эффективность
- •Пример 4.3.2
- •Глава 5 Структуры данных
- •5.1. Списки списковая форма записи
- •А на запрос
- •Некоторые стандартные целевые утверждения для обработки списков
- •5.2. Бинарные деревья представление бинарных деревьев
- •Бинарное дерево на рис.5.2.1 имеет левое поддерево
- •Представление множеств с помощью бинарных деревьев
- •Будем называть линейным представление такого вида, как на рис.5.2.3, и сбалансированным - такое, как на рис.5.2.2.
- •Левому поддереву соответствует отсортированный список
- •Глава 6 Операторы
- •6.1. Операторы и структуры синтаксис операторов
- •Свойства операторов
- •6.2. Позиция операторов
- •6.3. Приоритет операторов
- •6.4. Ассоциативность операторов
- •6.5. Спецификаторы
- •6.6. Операторы объявления
- •6.7. Пример: вычисление многочленов
- •6.8. Системные операторы
- •Глава 7 Механизм возврата и процедурная семантика
- •7.1. Механизм возврата
- •7.2. Пример: задача поиска пути в лабиринте
- •Целевое утверждение не удается согласовать с первым утверждением
- •Если мы введем
- •Если затем мы введем
- •7.3. Обработка фактов с помощью механизма возврата
- •7.4. Предикат repeat
- •7.5. Декларативная и процедурная семантики
- •Характеристики процедуры
- •7.6. Вопросы эффективности
- •Глава 8 Отсечение
- •8.1. Почему используют отсечение?
- •8.2. Использование отсечения
- •Выдав запрос
- •Обратившись к системе с запросом
- •8.3. Ловушки отсечения
- •Глава 9 Встроенные предикаты
- •9.1. Встроенные предикаты
- •9.2. Обновление базы данных Пролога
- •Добавление и удаление утверждений
- •Считывание утверждений в базу данных
- •Предикаты сохранения и восстановления
- •9.3. Особенности ввода и вывода чтение символов
- •Запись символов
- •Считывание термов Предикаты
- •Запись термов
- •9.4. Обработка файлов
- •Редактирование программ на прологе
- •Распечатка предикатов
- •Глава 10 Модули. Пример разработки системы
- •10.1. Модули
- •Пример 10.1.1
- •10.2. Пример разработки системы: деревья решений
- •Описание дерева решений
- •Разработка системы
- •Целевое утверждение
- •Глава 11 Отладка
- •11.1. Трассировка
- •Включение и выключение механизма трассировки
- •Необязательные параметры трассировки
- •Предикаты трассировки
- •Режимы трассировки
- •11.2. Установка контрольных точек
- •Возможные действия в контрольной точке
- •Включение и выключение режима контрольных точек
- •Необязательные параметры режима контрольных точек
- •Предикаты для работы с контрольными точками
- •Режимы, связанные с контрольными точками
- •Основные отладочные предикаты
- •Статистическая информация
6.2. Позиция операторов
Позиция оператора в выражении определяет его тип. Как было сказано выше, оператор может относиться к одному из трех типов.
Инфиксный - оператор располагается между двумя аргументами, например: X+Y или Х < Y.
Префиксный - оператор располагается перед единственным аргументом, например: not Х или - X.
Постфиксный - оператор располагается после единственного аргумента, например: Х факториал или Р прошло.
6.3. Приоритет операторов
Каждый оператор имеет приоритетный номер, указываемый при объявлении оператора. Номер является целым числом и обычно находится в пределах от 1 до 1500.
Если выражение содержит более одного оператора, например
X + Y * 2,
то возникает неопределенность в порядке выполнения операций. Эта проблема разрешается посредством назначения всем операторам приоритетного номера. Вычисления осуществляются, начиная с оператора, имеющего наименьший номер, и заканчивая оператором с наибольшим номером. В нашем примере Х + Y * 2 оператор * имеет более низкий приоритетный номер, чем оператор +. Поэтому, как и следовало ожидать, выражение вычисляется так: Х + (Y * 2).
Тео戲етический приоритетный номер скобок меньше нуля. Выражение, заключенное в скобки, рассматривается как один терм. Скобки могут использоваться для того, чтобы изменить правила установления ассоциативности и сделать синтаксис выражений более четким.
6.4. Ассоциативность операторов
Ассоциативность оператора указывает, как следует интерпретировать выражение, содержащее несколько операторов с одинаковым приоритетом. Покажем на примере необходимость такой информации.
Рассмотрим выражение а/b/с. Результат его вычисления зависит от расстановки скобок:
(а/b)/с или а/(b/с)
Арифметические операции +, -(минус), * и / определены в Прологе как левоассоциативные. Это означает, что они должны иметь слева операторы равного или низшего приоритета, а справа - операторы строго низшего приоритета.
Следовательно, приведенное выше выражение в соответствии с правилом можно вычислить только как (а/b)/с, а не как а/(b/с).
6.5. Спецификаторы
Позицию и ассоциативность оператора удобно задавать с помощью спецификатора. Перечислим виды спецификаторов:
fx для определения постфиксного оператора;
fv “”
xf для определения префиксного оператора;
yf “”
xfx для определения инфиксного оператора;
xfy “” (правоассоциативного оператора);
yfx “” (левоассоциативного оператора);
yfy “”
В такой форме записи приняты следующие соглашения:
f представляет оператор. Им может быть системный оператор или оператор, объявленный с помощью предиката ор;
х представляет выражение, содержащее операторы только низшего приоритета по отношению к приоритету f;
у представляет выражение, которое может содержать операторы равного или низшего приоритета по отношению к приоритету f.
Если оператор объявлен со спецификатором yfx, то он является левоассоциативным и подвыражение у вычисляется первым. Возьмем в качестве примера
5 + 4 * 10 / 5.
Здесь операторы * и / имеют одинаковый приоритет, но, поскольку они определяются в Прологе как левоассоциативные, выражение будет вычисляться следующим образом:
y f х
(5+4*10) / 5
(5+(4*10)) / 5
Следовательно, (5+(4*10))/5 равно 9, если использовать правило определения приоритета.
Если оператор объявлен со спецификатором xfy, то он является правоассоциативным и подвыражение у, стоящее справа, вычисляется первым.
Спецификатор yfy недопустим в Прологе, так как выражения, содержащие операторы с такой ассоциативностью, окажутся неопределенными. Если бы * и / были объявлены со спецификаторами yfy, тогда выражение из предыдущего примера 5+4*10/5 можно было бы вычислить либо как прежде
(5+(4*10))/5=9,
либо как
5+(4*(10/5))=13
(суммирование + объявлено с большим приоритетом, чем * или /).
Применение спецификатора xfx в Прологе допустимо. Он используется, например, при объявлении операторов сравнения, таких, как < и >. Обычно трудностей не возникает, так как для операторов < и > в Прологе определяется более высокий приоритет, чем для арифметических операторов. Следовательно, правая и левая части выражения должны быть вычислены до того, как будет произведена попытка выполнить функцию сравнения, например,
5+2 < 6+3
будет вычисляться как
(5+2) < (6+3)
Однако существует возможность построить синтаксически правильное выражение, которое не подчиняется потенциально неопределенным правилам установления приоритета и ассоциативности.
Примером может служить выражение Х opr Y opr Z, где оператор opr имеет позицию и ассоциативность xfx.
В тех случаях, когда приоритет и ассоциативность не определяют порядок вычисления операторов, в большинстве реализации Пролога первым выполняется оператор, стоящий слева.
Поэтому предыдущее выражение будет вычислено следующим образом:
(а opr b) opr c.
Если * > объявлен как левоассоциативный, а < * - как правоассоциативный оператор с помощью управляющих команд (директив)
?- op(60,yfy,*>).
?- op(60,xfy,<*).
то выражение а*>b*>с вычисляется как (а*>b)*>с, а<*b<*с вычисляется как а<*(b<*с) и а<*b*>с вычисляется как (а<*b)*>с по умолчанию.
Некоторые реализации Пролога в таких неясных случаях выдают сообщение об ошибке.