2.2. Типы данных
2.3. Константы и переменные
2.4. Программные секции Пролога
2.4.1. Секция Domains
2.4.2. Секция Predicates
2.4.3. Секция Database
2.4.4. Секция Clauses
2.4.5. Секция Goal
2.6. Примеры
Имена в
языке Prolog
используются
для обозначения
переменных,
символьных
констант,
объявлений
типов и
предикатов.
Имя может
начинаться с
любой
латинской буквы
или символа
подчеркивания
"_", затем следует
любая
комбинация
букв, цифр и
символа "_".
При
образовании
имен
необходимо
учитывать
следующие
правила:
- имена
строковых
констант
должны
начинаться с
маленькой
буквы либо
они должны
быть заключены
в кавычки;
- имена
переменных
должны
начинаться с
большой
буквы или символа
подчеркивания
"_".
Имена
предикатов
могут быть
записаны с любой
буквы или
символа
подчеркивания.
Имеется следующие основные стандартные типы данных:
|
symbol |
Символьная строка, которая начинается со строчной буквы или заключена в кавычки |
|
string |
Также символьная строка, но имеющая другое внутреннее представление |
|
char |
Отдельный символ, заключенный в апострофы |
|
integer |
Целое число в диапазоне от -32768 до 32767 |
|
real |
Вещественное число в диапазоне степеней 10 от -307 до +308 |
Константы
Пролога
должны быть
записаны:
а) либо с
маленькой
буквы
(исключая
кириллицу):
fact1, summa, person ;
б) либо
стоять в
одинарных
кавычках
(отдельный
символ) или
бинарных
кавычках
(строковая
константа):
'c' , "summa=",
"сумма" ;
в) либо они
являются
числами,
целыми или
вещественными:
25, 0.5, 3.2e-4 .
Таким
образом,
константы
могут быть
любого из
стандартных
типов
Пролога. В
программе
тип констант
явно не
указывается.
Переменные –
это цепочки,
состоящие из
букв, цифр и
символа
подчеркивания.
Имя
переменной
всегда начинается
с прописной
буквы или с
символа
подчеркивания:
X, Summa, List_of_members,
_x23.
Переменная
может иметь
один из
стандартных
типов, или
тип ее
определяется
в секции
описания областей
определения
(типов) domaims.
Можно также
использовать
так
называемую анонимную
переменную,
которая
записывается
в виде одного
символа
подчеркивания.
Программа на Прологе состоит из нескольких программных секций (разделов), каждой из которых предшествует ключевое слово, представленное в следующей таблице:
|
Domains |
Объявление областей определение данных (типов) |
|
Database |
Объявление предикатов базы данных |
|
Predicates |
Объявление предикатов |
|
Clauses |
Определение фактов и правил |
|
Goal |
Цель |
В программе
необязательно
наличие всех
секций.
Обычно в
небольшой
программе,
находящейся
в стадии
отладки,
присутствуют
разделы Predicates
и Clauses,
хотя, вообще
говоря, можно
обойтись
даже без них
(например,
когда
проверяется
работа
стандартного
предиката).
Для больших
программ
появляется
необходимость
в секции Domains
для
объявления
собственных
имен типов,
списков или
сложных
структур
данных.
Порядок
следования
программных
секций, как
правило,
соответствует
порядку,
приведенному
в таблице, т.е.
предикаты
должны быть
прежде
объявлены (в
секции Predicates),
а затем
следует их
реализация
(программирование)
в секции Clauses.
Единственное,
пожалуй,
исключение –
цель в
программе,
если она
есть, может
стоять в
любом месте,
Пролог все
равно
�прочешет� весь
код в поисках
цели, и
только если
ее не найдет,
запросит
цель
отдельно.
Обычно цель записывают
в конце
программы
как логическое
ее
завершение,
но если цель
стоит у вас в
середине, не
забудьте за
ней записать ключевое
слово,
соответствующее
продолжению
программы,
например Clauses.
В программе
может
использоваться
только одна
цель; если
цель не
указана,
Пролог цель
запросит.
Прочих
программных
секций может
быть сколько
угодно. Можно
описать
несколько
динамических
баз данных
или
несколько
объявлений предикатов
с дальнейшей
их
реализацией.
Ключевые
слова
разделов
можно
записывать
прописными и
строчными
буквами.
Комментарии
к программе
записываются
либо парами
символов слэш-звездочка:
/* это
комментарий,
он
занимает
несколько
строк */
либо остаток
строки
записывается
после знака
процента:
% это тоже
комментарий
Эта секция
является в
некотором
смысле аналогом
описания
типов
алгоритмических
языков, но со
своими
отличиями,
преимуществами
и,
соответственно,
недостатками.
Поскольку
описание
типов всегда
следует в начале
программы,
Пролог в этом
смысле не
является
исключением.
На первых
порах нужно,
наверно,
запомнить,
что для
объявления
секции domains
используются
всего четыре
следующих
способа
(формата):
1. Первый
формат
используется
для объявления
объектов,
которые
синтаксически
схожи, а
семантически
различны.
2. Второй
формат
используется
для объявления
списков –
одной из
основных
структур данных
Пролога.
3. Третий
формат
описывает
сложную
область
определения,
задает
описание
структур, позволяет
также
рекурсивно
описывать объекты
сложных
типов
(деревьев).
4. Четвертый
формат
описывает
файловый тип для
ссылки на
файлы по их
символическим
именам.
Сейчас мы
рассмотрим
только
первый способ,
поскольку он
нам может
понадобиться
в скором
времени, а
остальные
отложим до
лучших
времен,
поскольку
все равно из
головы выветрятся.
Описание
типов
списков
рассмотрим
сразу же со
списками,
структурных
типов – при
подробном
знакомстве
со
структурами, а
четвертый
файловый тип
вообще
отложим в долгий
ящик, для
наших
высокоуровневых
манипуляций
он не
потребуется,
в Прологе имеется
мощное
высокоуровневое
средство манипулирования
внешними
файлами.
Первый
формат используется
для
объявления
объектов,
которые
синтаксически
схожи, а
семантически
различны.
domains
name = t ,
где name –
имя Пролога,
выбираемое
пользователем
для своей
задачи;
t –
один из
стандартных
типов или
пользовательских,
т.е. ранее
определенных domains
Это
объявление
используется
для объектов,
которые
синтаксически
схожи, а
семантически
различны.
Например,
первое
предложение
domains
age, number = integer
r = real
объявляет
два domains целого типа.
Объявление
вида r
= real ускоряет
набор
программы.
Раздел domains
задает область
интерпретации
предметных
переменных,
т.е. теперь
две
переменные,
относящиеся
одна к типу age, а
другая – к number, уже не могут
быть
сопоставимы,
хотя обе остаются
переменными
целого типа.
Здесь указываются
все имена
предикатов с
соответствующими
областями
определения
аргументов.
Аргументы
дизъюнктов
Пролога
называются термами.
Существует
три типа
термов:
константа,
переменная,
составной
терм
(структура).
Описание
предикатов
включает в
себя имя
предиката и в
скобках –
перечисление
имен предметных
переменных
Общий вид
описания
предиката:
Predicates
name(domain1, domain2, ..., domainN)
,
где name – имя предиката, domain1,
domain2, ... domainN – соответственно области определения аргумента1, аргумента2 и т.д. Например:
Predicates
child( string
)
mother( string, string ) .
Допускается
множественное
определение предиката:
один и тот же
предикат
может быть
объявлен для
различного
числа
аргументов:
Predicates
hanoi
hanoi( integer
)
В этом случае для каждого предиката требуется своя реализация,
т.е. это по сути два разных предиката с одним и тем же именем.
Также можно объявить один предикат для аргументов разных типов:
Predicates
member( name,
namelist )
member( number, numberlist )
В этом случае отдельной реализации не потребуется.
Объявление
динамической
базы данных.
Синтаксис
объявления
такой же, как
и в секции Predicates.
Объявленные
здесь
предикаты не
должны объявляться
в секции Predicates,
но дизъюнкты
этих
предикатов
могут присутствовать
в секции Clauses.
Здесь записываются все дизъюнкты всех предикатов. Другое название дизъюнктов – статьи, предложения или клозы. Это факты и правила, соответствующие каждому из объявленных предикатов. Примеры записи дизъюнктов-фактов:
child( “Иван” ).
mother( “Анна”,
“Иван” ).
mother( “Анна”,
“Петр” ).
Каждый из дизъюнктов одного предиката секции
Clauses соответствует альтернативам этого предиката
(т.е.
реализация ИЛИ).
Главное синтаксическое требование при записи дизъюнктов – одноименные предикаты должны быть сгруппированы,
т.е. записаны последовательно один за другим.
Здесь указывается вопрос (цель), на который должен ответить Пролог. Записывается он как дизъюнкт без головы и знака ":–" , т.е. это конъюнкция подцелей. Например:
Goal
mother( “Анна”,
X ), mother( X, Y ).
При запуске программы цель выполняется автоматически.
Если все подцели в разделе Goal истинны,
программа завершается успешно. Если же какая-то подцель из раздела Goal ложна,
выполнение программы на этом заканчивается
и она
завершатся неуспешно.
Отметим, что запись цели явно в программе может отсутствовать.
Это режим называется режимом диалога, и служит он в основном для отладки отдельных предикатов. В режиме диалога
бэктрекинг включается автоматически,
т.е. получает все решения для указанной цели.
�Пример №1:
/*
Copyright (c) 1986, '92 by
predicates
�� repeat
�� action(integer,string)
�� test(string)
goal
�� makewindow(1,7,7,"interaction window",0,2,11,43),
�� repeat,
�� shiftwindow(1),
�� clearwindow,
�� write("0.
Enter 0 to end\n"),
�� write("1.
Enter 1 to create a window and input\n��
a new string\n"),
�� write("2.
Enter 2 to remove the window and text\n"),
�� write("3.
Enter 3 to write to existing window\n\n"),
�� write("Selection?
"),
�� readint(Int),nl,
�� action(Int,Text),
� �Int = 0,!,�������������� /* this cut will prevent
backtracking even if you
���������������������������������������������������
have not created a string */
�� test(Text).
clauses
�� action(0,"EXIT"):-!,���� /* this cut prevents PDC Prolog from
looking
�����������������������������������������������������������
at other options. */
����� exit.
�� action(1,Str):-
����� existwindow(2),
����� write("You
have a window that already exists.\n"),
����� write("Do
you wish to clear it.(y,n) "),
����� readchar(Ans),!,
����� Ans='y',��� /* If you answer yes to the question this
cut prevents the
�������������������������������� backtracking to the second action(1) clause. */
����� nl,
����� shiftwindow(2),
����� clearwindow,
����� write("Enter
your string\n"),
���� �readln(Str).
�� action(1,Str):-
!,�������� /* this cut prevents PDC
Prolog from looking
�����������������������������������������������������������
at other options. */
����� nl,
����� makewindow(2,7,7," simple window control ", 12, 3, 12, 40),
����� write("Enter
your string\n"),
����� readln(Str).
�� action(2,"window
removed"):-
����� existwindow(2),
����� !,��� /* If the window has been input, this cut
will prevent the second
��������������������������������������������� action(2) clause from executing */
����� shiftwindow(2),
����� removewindow,
����� clearwindow.
�� action(2,"ERROR"):-
����� clearwindow,
����� write("You
must first create a window\n"),
����� write("Press
any key to continue "),
����� readchar(_).
�� action(3,Str):-
����� existwindow(2),!,
����� shiftwindow(2),
����� clearwindow,
����� write("Enter
your string\n"),
����� readln(Str).
�� action(3,Str):-
����� write("There
is no window. Do you\n"),
����� write("want
to create one?(y/n) "),
����� readchar(ANS),
����� ANS = 'y',nl,
����� makewindow(2,7,7," simple window control ",12,3,12,40),
����� write("Enter
your string\n"),
����� readln(Str).
�� action(_,"ERROR"):-
����� write("not
a valid option\n"),
����� write("press
any key to continue").
�� test(Text):-
����� write(Text).
�� repeat.
�� repeat:-repeat.
Пример №2:
/*
Copyright (c) 1986, '92 by
predicates
�� can_buy(symbol, symbol)
�� person(symbol)
�� car(symbol)
�� likes(symbol,
symbol)
�� for_sale(symbol)
clauses
�� can_buy(X, Y) :-
����������� person(X),
����������� car(Y),
����������� likes(X,
Y),
�� �������� for_sale(Y).
�� person(kelly).
�� person(judy).
�� person(ellen).
�� person(mark).
�� car(lemon).
�� car(hot_rod).
�� likes(kelly, hot_rod).
�� likes(judy, pizza).
�� likes(ellen, tennis).
�� likes(mark,
tennis).
�� for_sale(pizza).
�� for_sale(lemon).
�� for_sale(hot_rod).