2. Основные элементы языка

2.1. Имена
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. Примеры

2.1. Имена

Имена в языке Prolog используются для обозначения переменных, символьных констант, объявлений типов и предикатов.
Имя может начинаться с любой латинской буквы или символа подчеркивания "_", затем следует любая комбинация букв, цифр и символа "_".
При образовании имен необходимо учитывать следующие правила:
- имена строковых констант должны начинаться с маленькой буквы либо они должны быть заключены в кавычки;
- имена переменных должны начинаться с большой буквы или символа подчеркивания "_".
Имена предикатов могут быть записаны с любой буквы или символа подчеркивания.

2.2. Типы данных

Имеется следующие основные стандартные типы данных:

symbol

Символьная строка, которая начинается со строчной буквы или заключена в кавычки

string

Также символьная строка, но имеющая другое внутреннее представление

char

Отдельный символ, заключенный в апострофы

integer

Целое число в диапазоне от -32768 до 32767

real

Вещественное число в диапазоне степеней 10 от -307 до +308

2.3. Константы и  переменные

Константы Пролога должны быть записаны:
а) либо с маленькой буквы (исключая кириллицу):
fact1,   summa,   person ;
б) либо стоять в одинарных кавычках (отдельный символ) или бинарных кавычках (строковая константа):
            'c' ,   "summa=",  "сумма" ;
в) либо они являются числами, целыми или вещественными:
             25,   0.5,   3.2e-4 .
Таким образом, константы могут быть любого из стандартных типов Пролога. В программе тип констант явно не указывается.
Переменные – это цепочки, состоящие из букв, цифр и символа  подчеркивания. Имя переменной всегда начинается с прописной буквы или с символа  подчеркивания:
      X,      Summa,      List_of_members,      _x23.
Переменная может иметь один из стандартных типов, или тип ее определяется в секции описания областей определения (типов) domaims. Можно также использовать так называемую анонимную переменную, которая записывается в виде одного символа подчеркивания.

2.4. Программные секции Пролога

Программа на Прологе состоит из нескольких программных секций (разделов), каждой из которых предшествует ключевое слово, представленное в следующей таблице:

Domains

Объявление областей определение  данных (типов)

Database

Объявление предикатов базы данных

Predicates

Объявление предикатов

Clauses

Определение фактов и правил

Goal

Цель

В программе необязательно наличие всех секций. Обычно в небольшой программе, находящейся в стадии отладки, присутствуют разделы  Predicates и  Clauses, хотя, вообще говоря, можно обойтись даже без них (например, когда проверяется работа стандартного предиката). Для больших программ появляется необходимость в секции Domains для объявления собственных имен типов, списков или сложных структур данных.
Порядок следования программных секций, как правило, соответствует порядку, приведенному в таблице, т.е. предикаты должны быть прежде объявлены (в секции Predicates), а затем следует их реализация (программирование) в секции Clauses. Единственное, пожалуй,  исключение – цель в программе, если она есть, может стоять в любом месте, Пролог все равно �прочешет� весь код в поисках цели, и только если ее не найдет, запросит цель отдельно. Обычно цель записывают в конце программы как логическое ее завершение, но если цель стоит у вас в середине, не забудьте за ней записать ключевое слово, соответствующее продолжению программы, например Clauses.
В программе может использоваться только одна цель; если цель не указана, Пролог цель запросит. Прочих программных секций может быть сколько угодно. Можно описать несколько динамических баз данных или несколько объявлений предикатов с дальнейшей их реализацией.
Ключевые слова разделов можно записывать прописными и строчными буквами.
Комментарии к программе записываются либо парами символов слэш-звездочка:
 /*  это комментарий,
      он занимает несколько строк  */ 
либо остаток строки записывается после знака процента:
% это тоже комментарий

2.4.1. Секция  Domains

Эта секция является в некотором смысле аналогом описания типов алгоритмических языков, но со своими отличиями, преимуществами и, соответственно, недостатками. Поскольку описание типов всегда следует в начале программы, Пролог в этом смысле не является исключением. На первых порах нужно, наверно, запомнить, что для объявления секции domains используются всего четыре следующих способа (формата):
1. Первый формат используется для объявления объектов, которые синтаксически схожи, а семантически различны.
2. Второй формат используется для объявления списков – одной из основных структур данных Пролога.
3. Третий формат описывает  сложную область определения, задает описание структур, позволяет  также рекурсивно описывать объекты сложных типов (деревьев).
4. Четвертый формат описывает файловый тип для ссылки на файлы по их символическим именам.
Сейчас мы рассмотрим только первый способ, поскольку он нам может понадобиться в скором времени, а остальные отложим до лучших времен, поскольку все равно из головы выветрятся. Описание типов списков рассмотрим сразу же со списками, структурных типов – при подробном знакомстве со структурами, а четвертый файловый тип вообще отложим в долгий ящик, для наших высокоуровневых манипуляций он не потребуется, в Прологе имеется мощное высокоуровневое средство манипулирования внешними файлами.
Первый формат используется для объявления объектов, которые синтаксически схожи, а семантически различны.


domains
name = t ,


где name – имя Пролога, выбираемое пользователем для своей задачи;
t – один из стандартных типов или пользовательских, т.е. ранее определенных  domains
Э
то объявление используется для объектов, которые синтаксически схожи, а семантически различны. Например, первое предложение


domains
age, number = integer

r = real


объявляет два domains целого типа. Объявление вида r = real ускоряет набор программы.
Раздел domains задает область интерпретации предметных переменных, т.е. теперь две переменные, относящиеся одна к типу age, а другая – к number, уже не могут быть сопоставимы, хотя обе остаются переменными целого типа.

2.4.2. Секция Predicates

Здесь указываются все имена предикатов с соответствующими областями определения аргументов. Аргументы дизъюнктов Пролога называются термами. Существует три типа термов: константа, переменная, составной терм (структура). Описание предикатов включает в себя имя предиката и в скобках – перечисление имен предметных переменных 
Общий вид описания предиката:


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 )


 В этом случае отдельной реализации не потребуется.

2.4.3. Секция Database

Объявление динамической базы данных. Синтаксис объявления такой же, как и в секции  Predicates. Объявленные здесь предикаты не должны объявляться в секции Predicates, но дизъюнкты этих предикатов могут присутствовать в секции Clauses.

2.4.4. Секция Clauses

Здесь записываются все дизъюнкты всех предикатов. Другое название дизъюнктов – статьи, предложения или клозы. Это факты и правила, соответствующие каждому из объявленных предикатов. Примеры записи дизъюнктов-фактов:


child( “Иван” ).
mother( “Анна”, “Иван” ).
mother( “Анна”, “Петр” ).


Каждый из дизъюнктов одного предиката секции Clauses соответствует альтернативам этого предиката (т.е. реализация ИЛИ).
Главное синтаксическое требование при записи дизъюнктов – одноименные предикаты должны быть сгруппированы, т.е. записаны последовательно один за другим.

2.4.5. Секция Goal

Здесь указывается вопрос (цель), на который должен ответить Пролог. Записывается он как дизъюнкт без головы и знака ":–" , т.е. это конъюнкция подцелей. Например:


Goal
mother
( “Анна”, X ), mother( X, Y ).


При запуске программы цель выполняется автоматически. Если все подцели в разделе Goal истинны, программа завершается успешно. Если же какая-то подцель из раздела Goal ложна, выполнение программы на этом заканчивается и она завершатся неуспешно.
Отметим, что запись цели явно в программе может отсутствовать. Это режим называется режимом диалога, и служит он в основном для отладки отдельных предикатов. В режиме диалога бэктрекинг включается автоматически, т.е. получает все решения для указанной цели.

2.5. Примеры

Пример №1:

 

/* Copyright (c) 1986, '92 by Prolog Development Center */

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 Prolog Development Center */

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).