
- •Приложение 4-5
- •IV. Версии языка пролог СиПролог Поставщик
- •Синтаксис и встроенные предикаты
- •Директивы
- •Среда для разработки программ
- •Отладчик
- •Отладочные команды
- •Компилятор
- •Запомненные состояния
- •Интерфейс с иными языками программирования
- •Расширения языка
- •Квинтус Пролог Поставщик
- •Синтаксис и встроенные предикаты
- •Директивы
- •Среда разработки программ
- •Отладчик
- •Компилятор
- •Запомненные состояния
- •Система программирования на Прологе фирмы Сайлоджик Поставщик
- •Синтаксис и встроенные предикаты
- •Директивы
- •Среда разработки программ
- •Отладчик
- •Компилятор
- •Запомненные состояния
- •Интерфейс с иными языками программирования
- •Расширения
- •Пролог-2 Поставщик
- •Синтаксис и встроенные предикаты
- •Директивы
- •Среда разработки программ
- •Отладчик
- •Компилятор
- •Запомненные состояния
- •Интерфейс с иными языками программирования
- •Расширения
- •Эрити Пролог Поставщик
- •Синтаксис и встроенные предикаты
- •Среда разработки программ
- •Отладчик
- •Компилятор
- •Запомненные состояния
- •Расширения
- •Унсв Пролог Поставщик
- •Синтаксис и встроенные предикаты
- •Директивы
- •Среда разработки программ
- •Отладчик
- •Компилятор
- •Запомненные состояния
- •Интерфейс с иными языками программирования
- •Турбо Пролог Поставщик
- •Синтаксис и встроенные предикаты
- •Среда разработки программ
- •Отладчик
- •Запомненные состояния
- •Интерфейс с иными языками программирования
- •Расширения
- •V. Ответы к упражнениям Ответы к упражнениям
- •Глава 2
- •Глава 3
- •Глава 5
- •Глава 6
- •Глава 7
Компилятор
Для Пролога-86 нет компилятора.
Запомненные состояния
В Прологе-86 нет ничего похожего на двоичные запомненные состояния СиПролога. Встроенный предикат "save/1", аргументом которого является имя файла, переписывает в файл в форме, доступной для восприятия человеком, все фразы текущей программы. При этом, если во фразах есть переменные, то они будут представлены своими внутренними именами.
Интерфейс с иными языками программирования
Если в Вашем распоряжении имеется исходный текст УНСВ Пролога, то в него можно добавить в качестве дополнительных встроенных предикатов функции, написанные на языке Си.
Разное
Имеется встроенный предикат "eof", который будет истинным, если встретится состояние "конец файла" для текущего входного потока.
Ниже приводится текст библиотеки, обеспечивающей совместимость Пролога-86 с DEC-10 Прологом, что позволит выполнять в Прологе-86 программы из данной книги.
% Библиотека совместимости для % Пролога-86. Добавьте ее в файл
% "prolog. lib" или "prolog_lib"
% вместо встроенного предиката "name"
% пользуйтесь нижеследующие предикатом:
decl0name (atom, ИСписок) :—
nonvar (ИСписок),
char_ _list (ИСписок, ССписок),
name (Атом, ССписок),!.
declOname (Атом, ИСписок) : -
atom (Атом),
name (atom, ССписок),
char__list (ИСписок, ССписок), !.
get0(l): - getc(C), ascii(C, I), !.
put(l) :- ascii(C, I), putc(C),!.
:- op(700,xfy,=<).
X=<Y:-X<=Y.
:- op(700,xfx,==).
X==Y:- not(X=Y).
Турбо Пролог Поставщик
Турбо Пролог поставляется фирмой Борленд Интернэшнл. Он работает под управлением операционной системы MS-DOS на ЭВМ IBM PC и совместимых с ними компьютерах.
Турбо Пролог - это компилятор (не интерпретатор!). Он отличается высокой скоростью компиляции и выполнения. Среда разработки программ Турбо Пролога на первый взгляд кажется превосходной, но на самом деле это не совсем так. Программа, написанная на Турбо Прологе, сильно отличается от других Пролог-программ, так как она всегда должна начинаться с директив компилятора. Общий вид программы:
trace /* по желанию */
project "название проекта" / * по желанию */
include "другой_исходный_файл"/* по желанию */
domains /* по желанию; объявляет */
лицо = symbol /* новые типы областей значений */
смена = symbol
database /*пожеланию; */
работает (лицо, смена) /* объявляет преди- */
/* каты, которые можно */
/ * добавлять и удалять */
predicates /* обязательно, объявляет * /
знает (лицо, лицо) /* область */
/ * каждого аргумента) * /
goal /* по желанию */
знает (А, В).
clauses /* как правило, необходимо; */
/* здесь располагается сам * /
/* текст программы */
работает (билл, дневная).
работает (нэнси, дневная).
знает (X,Y) :-
работает(Х,S),
работает (Y,S),
X<>Y.
Если в программе есть директива "goal" (цель), то при выполнении программы система прогона вычислит эту цель один раз и закончит программу. Если в программе нет директивы "goal", то во время выполнения программы пользователь может вводить запросы. Смысл других директив излагается ниже.
Синтаксис и встроенные предикаты
Синтаксис Турбо Пролога в значительной мере аналогичен синтаксису DEC-10 Пролога. Многие программы данной книги без каких-либо переделок будут работать под Турбо Прологом.
В качестве синонима символического обозначения : - можно использовать слово "if (если), вместо ; можно использовать слово "or" (или), а вместо , — слово "and" (и). Комментарии в Турбо Прологе записываются между символами / * и * /. Символ % не является признаком комментария.
В Турбо Прологе имеются некоторые встроенные предикаты, аналогичные предикатам DEC-10 Пролога.
Приведем встроенные предикаты Турбо Пролога, эквивалентные некоторым часто используемым встроенным предикатам DEC-10 Пролога:
DEC-10 Пролог |
Турбо Пролог |
Пояснения |
is/2 |
=/2 |
арифметическое вычисление |
var/1
|
free/1 |
успешен, если аргументом является неконкретизированная переменная |
nonvar/1 |
bound/1 |
успешен, если аргументом не является неконкретизированная переменная |
\==/2 |
< >/2 |
успешен, если аргументы не одинаковы |
get0/1 |
readchar/l |
считывает символы с текущего входного устройства |
В Турбо Прологе отсутствует предикат, эквивалентный предикату " =/2" DEC-10 Пролога (этот предикат унифицирует два любых терма). В Турбо Прологе невозможно определить операции.
В Турбо Прологе имеются встроенные предикаты "asserta", "assertz" и "retract", предназначенные для модификации текущей программы. Однако, в отличие от других описанных здесь версий Пролога, аргументами этих трех предикатов должны быть только факты, а не правила. Любой предикат, фразы которого предполагается удалять и добавлять, должен быть объявлен как предикат базы данных при помощи директивы компилятора "database". К примеру, предикат "работает/2" объявлен в приведенном выше участке исходного файла как предикат базы данных.
У встроенного предиката "write" может быть любое число аргументов. Существует встроенный предикат "writef", первым аргументом которого должна быть строка форматов. После первого аргумента может располагаться произвольное количество других аргументов. В Турбо Прологе отсутствует предикат, эквивалентный встроенному предикату "read/1" DEC-10 Пролога, но имеются предикат "readln/1", считывающий строку символов, и предикат "readtenn/2", который считывает терм. Первым аргументом встроенного предиката "readtenn/2" должна быть спецификация области значений, которая определяет то, какие типы термов может считывать данный предикат (см. ниже подраздел о типах) .
Вместо встроенных предикатов "see", "tell" и т.д. в Турбо Прологе имеются следующие предикаты, предназначенные для управления файлами:
openread(N,F)
openwrite(N, F)
openappend(N, F)
openmodify(N, F)
Здесь F — имя файла в операционной системе MS-DOS, N — внутреннее имя, выбранное программистом, которое будет использоваться при обращении к открытому файлу. Встроенный предикат "openread" открывает файл для чтения. Встроенный предикат "openwrite" открывает файл для записи. Встроенный предикат "openappend" открывает файл для добавления записей в конец файла. Встроенный предикат "openmodify" открывает файл и для чтения, и для записи. В файл произвольного доступа можно внести изменения, если он открыт при помощи встроенного предиката "openmodify", а для позиционирования указателя записи используется встроенный предикат "filepos/3".
writedevice(N)
N — внутреннее имя файла, открытого при помощи встроенного предиката "openwrite", "openmodify" или "openappend". Этот предикат соотносит файл с текущим устройством вывода, так что выходная информация, вырабатываемая при любых вызовах встроенного предиката "write" или "writef", пойдет в этот файл.
readdevice(N)
N — внутреннее имя файла, открытого при помощи встроенного предиката "openread". Этот предикат соотносит файл с текущим входным устройством, так что информация, вводимая при любых обращениях к встроенным предикатам "readchar/1", "readln/1", "readint/1", "readreal/1" или "readterm/2", будет поступать из этого файла.
closefile(N)
N —внутреннее имя открытого файла. Данный встроенный предикат закрывает этот файл.
Арифметические функции
Арифметические операторы ("=", "<" и т.д.) в дополнение к обычным арифметическим операциям позволяют вычислять ряд функций, среди которых в первую очередь нужно отметить следующие:
abs(X) % абсолютное значение Х
sqrt(X) % квадратный корень из X
ехр(Х) % число е в степени Х
log(X) % десятичный логарифм Х
1n(Х) % натуральный логарифм Х
sin(X)
cos(X)
tan(X)
arctan(X)
и т.д.
Типы
Турбо Пролог отличается от других версий Пролога тем, что в нем должен быть объявлен тип области значений (domain type) для всех аргументов каждого предиката. В Турбо Прологе изначально имеются нижеследующие простые типы области значений:
char
integer
real
string
symbol
file
К типу «char» относятся одиночные символы, к типу «symbol» — атомы.
Типы «string» и «symbol» взаимозаменяемы, хотя они и имеют различное внутреннее представление. Приведем простой пример, показывающий, как можно определить новые типы области значений через простые типы и как типы области значений употребляются в объявлениях предикатов:
domains
имя = symbol predicates
сделка (имя, real) clauses
сделка (боб, 37.50).
сделка (мери, 4.75).
сделка (сью_элен, 50.00).
Поскольку в объявлении области значений записано «имя = symbol», «имя» становится новым типом области значений, совпадающей с областью «symbol». Если при выполнении данной программы пользователь попытается воспользоваться запросом к предикату "сделка", задавая неверные типы области значений, то Турбо Пролог выдаст сообщение об ошибочном использовании типов области значений.
Структуры можно определять как новые типы -области значений, выражая их через простые типы области значений. Приведем версию программы "сделка" из разд. 2.2. Оба аргумента предиката "сделка" являются структурами.
domains
имя = symbol
сумма = integer
структура_клиент = клиент (имя, сумма, integer)
структура_дата = дата (integer, integer, integer) predicates
сделка (структура_клиент, структура_дата) clauses
сделка (клиент (смит, 29,4), дата (87,4,22) ).
сделка (клиент (ли, 35,7) , дата (86,10,30) ).
Если одним из аргументов предиката является список, то область значений этого аргумента следует объявить как объект*, где «объект» — это область значений каждого элемента списка. Приведем в качестве примера версию процедуры "member", которая будет работать со списком, включающим целые числа:
domains
список—целых = integer*
predicates
member (integer, список_целых)
clauses
member (X, [X | _]).
member (X, [_ | Y] ) :- member (X, Y).
В данной программе проявляется недостаток принятой в Турбо Прологе строгой типизации: если пользователь напишет запрос к процедуре "member", аргументом в котором будет список, содержащий атомы, действительные числа или структуры, то Турбо Пролог выдаст сообщение об ошибочном использовании типа области значений и не будет выполнять программу. На практике это означает, что программист должен предусмотреть заранее, элементы каких типов могут попадаться в списке, который будет аргументом процедуры "member", и включить их в объявление областей значений. Тем самым необходимость объявления областей значений существенно уменьшает потенциальную возможность использования составленной программы в каких-либо других целях. Помимо этого, становится невозможным написание предикатов метаязыка, см. ниже подраздел "Разное".
Очевидно, что объявления типов областей значений сильно влияют на работу алгоритма унификации в Турбо Прологе. Вообще говоря унификация терма, находящегося в запросе, с термом из фразы программы может произойти только в том случае, если во время компиляции программы эти термы были объявлены с совместимыми типами области значений.
Строки
Перечислим имеющиеся в Турбо Прологе встроенные предикаты, предназначенные для работы со строками.
readln (Строка)
Этот предикат считывает запись данных с текущего входного устройства и возвращает ее в виде строки.
frontchar (Строка, ПервСимв, Остаток)
Этот предикат берет первый символ из начала строки и возвращает оставшуюся часть строки через «Остаток».
frontstr(N, Строка, Начало, Конец)
Здесь N - целое число, «Строка» - это строка по меньшей мере из N символов. Данный предикат возвращает первые N символов строки «Строка» через переменную «Начало» (которая также является строкой), а остальные символы строки «Строка» — через переменную «Конец».
fronttoken (Строка, Признак, Остаток)
Если переменная «Строка» конкретизирована, то данный предикат находит первое слово или число, содержащееся в переменной «Строка», и возвращает его через переменную «Признак». Остаток строки возвращается через переменную «Остаток».
str_len (Строка, Длина)
Данный предикат возвращает число символов, содержащихся в строке «Строка».
Преобразование типов
В Турбо Прологе имеются нижеследующие встроенные предикаты, предназначенные для преобразования значений от одного типа к другому:
str_char (Строка, Символ)
str_int (Строка, Целое)
str_real (Строка, Действительное)
/ * преобразовать ascii-код в соот- */
/* ветствующий ему символ: */
char_int (Символ, Целое)
/* преобразовать строку, приведя ее */
/* целиком либо к буквам верх- */
/* него регистра (заглавные буквы), */
/* либо к буквам нижнего ре - */
/* гистра (строчные буквы) */
upper_lower (Верх_Строка, Ниж_Строка)