2. Синтаксис и семантика пролог программ
2.1. Синтаксис Пролога
Общий
синтаксис
программ на
языке Пролог можно описать следующей
грамматикой:
<программа>::=<предложение>
| <программа> <предложение>
<предложение>::=<утверждение>
| <запрос> | <команда>
<утверждение>::=<факт> |
<правило>
<факт>
=<терм>.
<правило>
=<терм>:-<термы>.
<запрос>
=?-<термы>.
<команда>
=:-<терм>.
<термы>::=<терм>
| <термы>,<терм>
<терм>
=<атом> | <структура> | <константа>
| <переменная>
<структура>
=<атом>(<термы>)
<атом>
=<идент> | '<символы>' |
<слецсимволы>
<константа>
=<число> | <строка>
<строка>
="<символы>"
Комментарии
записываются либо в скобках /* */, либо
после символа % до конца строки. ^
Команда
(директива)
используется для управления процессом
трансляции программы во внутреннее
представление. Логическая программа
состоят из определений предикатов.
Предикат
(отношение) -
это элементарная формула в логическом
выражении, которая является истинной,
если выполняется ли некоторое свойство
или отношение для указанных аргументов,
и ложной в противном случае. Определение
предиката
позволяет проверить истинность предиката
и состоит из набора фактов и правил
с одинаковым именем и количеством
аргументов (предикат с именем name и двумя
аргументами часто обозначают как
name/2). Язык Пролог не включает средств
для указания типа аргументов, и
аргументами предикатов могут быть
произвольные термы, при этом аргументы
не вычисляются, а передаются в виде
термов, являющихся основной структурой
данных в логических программах. Тело
правила и запрос должны содержать
обращения только к встроенным или
определяемым в программе предикатам.
Обычно
для программирования на языке Пролог
достаточно только целых чисел, но
большинство интерпретаторов допускает
использование также и вещественных
чисел. Строки в Прологе рассматриваются
как списки кодов символов, что позволяет
их обрабатывать так же, как и другие
списки. Некоторые версии интерпретаторов
могут включать в себя и другие типы
констант.
Атомы используются как
имена для объектов и отношений в
программе.
В качестве имени
можно использовать:
1) традиционный
идентификатор, состоящий из букв, цифр
и символов "_" и начинающийся со
строчной буквы;
2) произвольную
последовательность символов а
апострофах (т е даже неадаптированная
версия интерпретатора допускает
использование русских наименований);
3)
последовательность специальных
символов, которым относятся +-*/=\== & ~
и др.
Пример.
Следующие
цепочки являются
атомами:
atom
x_23
'Наташа'
::=
Переменная
в логической программе используется
только как ссылка на конкретный
объект. Переменная, еще не имеющая
значения, называется неконкретизированной.
Имя переменной состоит из буке, цифр и
символов "_" и начинается с прописной
латинской буквы или символа подчеркивания.
Область действия переменной ограничена
одним предложением. Если переменная
при согласовании цели получит какое-либо
значение, то значение этой переменной
не может быть изменено в ходе дальнейшего
логического вывода, так как подобное
изменение могло бы повлечь изменение
истинности проверенных ранее предикатов.
Переменная с именем "_" называется
анонимной.
Анонимные переменные избавляют
программиста от необходимости давать
имена переменным, которые используются
в предложении только один раз. После
трансляции программы, каждому вхождению
анонимной переменной соответствует
своя временная переменная.
Пример.
Определение
наличия детей при определенном предикате
parent:
haschald(X):-parent(X, _).
Значение
анонимной переменной не выводится на
печать. Если несколько анонимных
переменных, то они все разные. Использование
анонимных переменных позволяет не
выдумывать имена переменных, когда не
надо.
Если в языке Lisp данные
принято в основном представлять в виде
списков, то в Прологе основной формой
представления являются структуры.
Структура состоит из функтора (имени
структуры) и набора компонент (составных
частей структуры). Число аргументов
функтора называется арностью.
Для структур удобно использовать
графическое представление в виде
дерева, корнем дерева является функтор,
а ветвями - компоненты. Как набор структур
представляется и текст программы. Это
позволяет программам интерпретировать
свой текст как данные, вносить изменения
в программу в процессе выполнения.
Пример.
Дату можно
рассматривать как структуру, состоящую
из трех компонент: день, месяц, год. Хотя
они и составлены из нескольких компонент,
структуры в программе ведут себя как
единые объекты. Для того, чтобы объединить
компоненты в структуру, требуется
выбрать функтор.
Для нашего примера выберем функтор
дата. Тогда дату 1-е мая 1983 г. можно
записать так: дата(1, май, 1983). Все компоненты
в данном примере являются константами
(две компоненты - целые числа и одна -
атом). Компоненты могут быть также
переменными или структурами.
Все
структурные объекты можно изображать
в виде деревьев (пример см. на рис. 2.2).
Корнем дерева служит функтор, ветвями,
выходящими из него, - компоненты. Если
некоторая компонента тоже является
структурой, тогда ей соответствует
поддерево в дереве, изображающем весь
структурный объект.
Рис.
3.2.1. Дата - пример структурного
объекта:
(а) его представление
в виде дерева; (б)
запись на Прологе.
Арифметическое
выражение также можно представить как
некоторую структуру например, выражение
х+2*у может быть записано как +(х,*(2,у))
Такая форма сложнее для восприятия, но,
к счастью, язык Пролог позволяет
определить функторы как операторы
с нужными свойствами (приоритетом,
позицией и ассоциативностью) и использовать
привычную форму записи арифметических
выражений и предикатов. Для этого
используется команда:
:-ор(приоритет,
тип, функтор).
Если оператор
инфиксный, то указывается тип xfx, xfy
(правоассоциативный) или yfx
(левоассоциативный). Для постфиксного
оператора указывается тип xf или yf для
префиксного - fx или fy. Буква f указывает
расположение функтора, буква х указывает
на аргумент, чей приоритет должен быть
строго выше приоритета оператора, а
буква у обозначает аргумент с приоритетом
выше или равным приоритету оператора.
В таблице 3.2.1 показан приоритет
предопределенных операторов.
Тип |
Позиция |
Ассоциативность |
xfx |
инфиксный |
неассоциативный |
xfy |
инфиксный |
правоассоциативный |
yfx |
инфиксный |
левоассоциативный |
fx |
постфиксный |
неассоциативный |
fy |
постфиксный |
правоассоциативный |
xf |
префиксный |
неассоциативный |
yf |
префиксный |
левоассоциативный |
Таблица 3.2.1. Типы (ассоциативность) операторов Приоритет оператора должен быть в диапазоне от 1 до 1200, самый высокий приоритет - 1, самый низкий - 1200. Тип оператора определяет его позицию и ассоциативность.
Встроенный оператор (функтор) |
Тип |
Приоритет |
?- :- --> |
xfx |
1200 |
:- |
fx |
1200 |
; |
xfy |
1100 |
, |
xfy |
1000 |
not \+ |
fy |
900 |
-> |
xfy |
800 |
= |
xfy |
700 |
is \== \= == |
xfx |
700 |
=\= =:= |
xfx |
650 |
>= > =< < |
xfx |
600 |
>> << |
yfx |
550 |
- + |
yfx |
500 |
: |
xfy |
500 |
- + |
fx |
500 |
mod // / * |
yfx |
400 |
^ |
xfy |
300 |
\ * & |
fy |
300 |
Таблица 3.2.2. Приоритет предопределенных операторов При необходимости программист может ввести свои операторы или переопределить существующие. Пример. Определив оператор «нравится» как: :-op(600, xfx, likes) можно записать факт того, что Мэри нравится кино likes(mary, cinema). в более естественном виде: mary likes cinema. В Прологе выполняются следующие арифметические операции: + - сложение - - вычитание * - умножение / - деление mod - остаток от целочисленного деления. // - целочисленное деление ^ - возведение в степень Поддерживается ряд стандартных математических функций (sqrt, sin, random и др.) Пример. Если записать: x = 2+1. то получим результат: X=2+1 т.к. это просто сопоставление переменной и структуры. Чтобы арифметическое выражение рассчитывалось, необходимо использовать встроенный оператор is, который заставляет выполнять арифметические операции. Пример. Вычисление суммы двух целых чисел. X is 2+1. X=3 В арифметических выражениях могут встречаться и переменные, но они должны иметь значение к моменту вычисления. Пример. Вычисление суммы квадратов двух чисел. f(X, Y, Z):-Z is X*X + Y*Y. ?- f(3,4,X). X=25; No К операциям сравнения относятся следующие предикаты: =:= - проверка на равенство =\= - проверка на неравенство > - отношение «больше» < - отношение «меньше» =< - отношение «меньше либо равно» (запомнить порядок!) >= - отношение «больше либо равно» Пример. Проверка на равенство суммы двух чисел их произведению. ?- 2+2=:=2*2 С помощью операций сравнения можно создавать запросы на выборку фактов, удовлетворяющих заданным условиям. Пример. Из заданных фактов возрастов, выделим те, что лежат в указанном диапазоне. age(mary, 20). age(ann , 23). age(bob , 25). ?- age(X, Y), Y>21, Y=<23. X=ann; Y=20; Пролог позволяет формировать сложные логические выражения. Простейшими логическими предикатами являются true (истина) и fail (ложь, неудача) Согласование цели true всегда успешно. Согласование цели fail всегда неудачно Для конъюнкции целей используется предикат "," (X,Y), а для дизъюнкции - предикат "," (X;Y) Приоритет у оператора "," выше, чем у оператора ",", поэтому лишние скобки можно опускать. Пример. Выражение A,B,C,D интерпретируется как (A,B),(C,D) Для отрицания используется предикат not(X). Так как запятая служит как для конъюнкции целей, так и для разделения аргументов, требуются дополнительные скобки, если аргумент not не является элементарным выражением. Например, нужно писать not((A,B)), а не not(A,B) Конструкция "если А то В иначе С" на языке Пролог может быть записана как (A,B,not(A) С) или (А,В,С), а конструкция "если А то В" - как (A,B,true) Можно даже ввести условный оператор в язык, задав необходимые операторы и предикаты Пример. Зададим условные операторы и запишем с их помощью определение прдиката max :-op(1160, fx, if). :-op(1150, xfx, then). :-op(1155, xfx, else). if A then B else C :- A, B; not(A), C. max(X,Y,Z) :- if X>Y then Z is X else Z is Y.
