Рассмотрим следующий фрагмент программы:
constants
zеrо = О
one = 1
two = 2
hundred = (10*(10-1)+10)
pi = 3.141592653
ega = 3
slash_fill = 4
red = 4
Перед компиляцией программы VisualProlog заменит каждую константу на соответствующую ей строку.
На использование символических констант накладываются следующие ограничения:
· описание константы не может ссылаться само на себя:
my_number = 2*my_number/2 % не допускается
· это приведет к сообщению об ошибке "Recursioninconstantdefinition" (Рекурсия в описании константы);
· в описаниях констант система не различает верхний и нижний регистры. Следовательно, при использовании в разделе программы clauses идентификатора типа constants, его первая буква должна быть строчной для того, чтобы избежать путаницы между константами и переменными.
· в программе может быть несколько разделов constants, однако объявление константы должно производиться перед ее использованием;
· идентификаторы констант являются глобальными и могут объявляться только один раз. Множественное объявление одного и того же идентификатора приведи к сообщению об ошибке "Constantidentifiercanonlybedeclaredonce" (Идентификатор константы может объявляться только один раз).
VisualProlog поддерживает несколько директив компилятора, которые можно добавлять в программу для сообщения компилятору специальных инструкций по обработке вашей программы при ее компиляции. Кроме этого, вы можете устанавливать большинство директив компилятора с помощью команды меню среды визуальной разработки VisualPrologOptions/Project/CompilerOptions.
Директива include
Для того чтобы избежать многократного набора повторяющихся процедур, вы можете использовать директиву include.
Ниже приведен пример того, как это делается.
1. Создаете файл (например, MYSTUFF.PRO), в котором объявляете свои наиболее I часто используемые предикаты (с помощью разделов domains и predicates) и даете их описание в разделе clauses.
2. Пишете исходный текст программы, которая будет использовать эти процедуры.
3. В "допустимых областях" исходного текста программы размещаете строку:include "mystuff.pro"
"Допустимые области" — это любое место программы, в котором вы можете расположить декларацию разделов domains, facts, predicates, clauses или goal.
При компиляции исходных текстов программы VisualProlog вставит содержание файла MYSTUFF.PRO прямо в окончательный текст файла для компиляции.
Директиву include можно использовать для включения в исходный текст (практически любого) часто используемого фрагмента. Кроме того, любой включаемый в программу файл может, в свою очередь, включать другой файл (однако каждый файл может быть включен в вашу программу только один раз).
II. Унификация и поиск с возвратом
Рассмотрим программу ch04e01.pro (рис.1) с точки зрения того, как утилита TestGoal будет отыскивать все решения следующей цели written_by(X, Y).
domains
title, author = symbol
pages= unsigned
predicates
book(title, pages)
written_by(author, title)
long_novel (title)
clauses
written_by(fleming, "DR NO").
written_by(melville, "MOBY DICK").
book("MOBY DICK", 250).
book("DR NO", 310).
long_novel (Title) :-
written_by(_, Title),
book(Title, Length),
Length > 300.
Рис. 1. Листинг программы ch04e01.pro
Пытаясь выполнить целевое утверждение written_by(X, Y), VisualProlog должен проверить каждое предложение written_by(X, Y) в программе. Сопоставляя аргументы X и Yс аргументами каждого предложения written_by, VisualProlog выполняет поиск от начала программы до ее конца. Обнаружив предложение, соответствующее целевому утверждению, VisualProlog присваивает значения свободным переменным таким образом, что целевое утверждение и предложение становятся идентичными. Говорят, что целевое утверждение унифицируется с предложением. Такая операция сопоставления называется унификацией.
Поскольку X и Yявляются свободными переменными в целевом утверждении, а свободная переменная может быть унифицирована с любым другим аргументом (и даже с другой свободной переменной), то целевое утверждение может быть унифицировано с первым предложением written_by в программе, как показано ниже:
written_by (X,Y).
¯¯
written_by(fleming,"DR NO").
VisualProlog устанавливает соответствие, X становится связанным с fleming, aY – “drno”. В этот момент VisualProlog напечатает:
X=fleming, Y="DR NO"
Поскольку TestGoal ищет все решения для заданной цели, целевое утверждение также будет унифицировано и со вторым предложением written_by:
written_by(melville, "MOBY DICK").
TestGoal печатает второе решение:
X=melville, Y="MOBY DICK"
2 Solutions
Рассмотрим, как VisualProlog выполнит следующее целевое утверждение:
long_novel(X).
Когда VisualProlog пытается выполнить целевое утверждение, он проверяет, действительно ли обращение может соответствовать факту или заголовку правила. В нашем случае устанавливается соответствие с
long_novel(Title)
VisualProlog проверяет предложение для long_novel, пытаясь завершить сопоставление унификацией аргументов. Поскольку в целевом утверждении X - свободная переменная, то она может быть унифицирована с любым другим аргументом. Title также не является связанным в заголовке предложения long_novel. Целевое утверждение соответствует заголовку правила, и унификация выполняется. Впоследствии VisualProlog будет пытаться согласовывать подцели с правилом
long_novel(Title) :-
written_by(_, Title), book(Title, Length), Length>300.
Пытаясь выполнить согласование тела правила, VisualProlog обратится к первой подцели в теле правила — written_by(_, Title). Поскольку авторство книги является несущественным, на месте аргумента author появляется анонимная переменная (_). Обращение written_by (_, Title) становится текущей подцелью, и Пролог ищет решение для этого обращения.
Пролог ищет соответствие с данной подцелью от вершины и до конца программы. В результате достигается унификация с первым фактом для written_by, а именно:
written_by(_, Title),
¯¯
written_by (fleming, "DR NO").
Переменная Title связывается с "drno", и к следующей подцели book (Title, Length) обращение выполняется уже с этим значением переменной. Далее VisualProlog начинает очередной процесс поиска, пытаясь найти соответствие с обращением к book. Так как Title связан с "drno", фактическое обращение выглядит как book("DRNO", Length). Процесс поиска опять начинается с вершины программы. Заметим, что первая попытка сопоставления с предложением book(“MOBYDICK", 250) завершится неудачно, и VisualProlog перейдет ко второму предложению book в поиске соответствия. Здесь заголовок книги соответствует подцели, и VisualProlog связывает переменную Length с величиной 310.
Теперь третье предложение в теле long_novel становится текущей подцелью:
length > 300.
VisualProlog выполняет сравнение, завершающееся успешно: 310 больше, чем 300. В этот момент все подцели в теле правила выполнены, и, следовательно, обращение long_novel(X) успешно. Так как X в обращении был унифицирован с переменной Title в правиле, то значение, с которым связывается Title при подтверждении правила, возвращается и унифицируется с переменной X. Переменная Title в случае подтверждения правила имеет значение "drno", поэтому VisualProlog выведет:
X="DR NO"
1 Solution.
Часто при решении реальной задачи мы придерживаемся определенного пути для ее логического завершения. Если полученный результат не дает искомого ответа, мы должны выбрать другой путь.
Так, вам, возможно, приходилось играть в лабиринт. Один из верных способов найти конец лабиринта — это поворачивать налево на каждой развилке лабиринта до тех пор, пока вы не попадете в тупик. Тогда следует вернуться к последней развилке и попробовать свернуть вправо, после чего опять поворачивать налево на каждом встречающемся распутье. Путем методичного перебора всех возможных путей вы, в конце концов, найдете выход.
VisualProlog при поиске решения задачи использует именно такой метод проб и возвращений назад; этот метод называется поиск с возвратом. Если, начиная поиск решения задачи (или целевого утверждения), VisualProlog должен выбрать между альтернативными путями, то он ставит маркер у места ветвления (называемого точкой отката) и выбирает первую подцель, которую и станет проверять. Если данная подцель не выполнится, VisualProlog вернется к точке отката и попробует проверить другую подцель.
predicates
likes(symbol,symbol)
tastes(symbol, symbol)
food(symbol)
clauses
likes(bill,X):-
food(X), tastes(X,good) .
tastes(pizza,good).
tastes(brussels_sprouts,bad).
food(brussels_sprouts).
food(pizza).
Рис. 2. Программа ch04e02.pro
Эта маленькая программа составлена из двух множеств фактов и одного правила. Правило, представленное отношением likes, утверждает, что Билл любит вкусную пищу.
Чтобы увидеть, как работает поиск с возвратом, дадим программе для решения следующее целевое утверждение:
likes(bill, What).
Когда Пролог пытается произвести согласование целевого утверждения, он начинает поиск с вершины программы.
В данном случае Пролог будет искать решение, производя с вершины программы поиск соответствия с подцелью likes (bill, what).
Он обнаруживает соответствие с первым предложением в программе и переменная What унифицируется с переменной X. Сопоставление с заголовком правила заставляет VisualProlog попытаться удовлетворить это правило. Производя это, он двигается по телу правила и обращается к первой находящейся здесь подцели: food(X).
Если выполняется новое обращение, поиск соответствия для этого обращения вновь начинается с вершины программы.
Пытаясь согласовать первую подцель, VisualProlog (начиная с вершины) производит сопоставление с каждым фактом или заголовком правила, встреченным в программе.
Он обнаруживает соответствие с запросом у первого же факта, представляющего отношение food. Таким образом, переменная X связывается со значением brussels_sprouts. Поскольку существует более чем один возможный ответ на обращение food(X), VisualProlog ставит точку возврата (маркер) возле факта food(brussels_sprouts). Эта точка поиска с возвратом указывает на то место, откуда Пролог начнет поиск следующего возможного соответствия для food(X).