*?- [test]. likes/2
Yes
*?- listing(likes/2).
likes(john,alfred).
likes(alfredjohn).
likes(bertrandjohn).
likes(david,bertrand).
likes(john,ANYBODY):- likes(ANYBODY,bertrand).
Yes
Переменные (в данном случае ANYBODY) записаны прописными буквами как в Прологе-10. Однако в МПрологе предусмотрена особая возможность сохранения символьных имен переменных в пользовательской программе.
Альтернативным способом вывода заданного предиката или некоторых из определяющих его утверждений является использование команды type:
* type likes/2
likes(john,alfred).
likes(alfred,john).
likes(bertrand,john).
likes(david,bertrand).
likes(john,ANYBODY):- likes(ANYBODY,bertrand).
Второе и четвертое утверждения данного предиката можно просмотреть с помощью команды;
* type likes / 2 CL (2,4)
likes(alfred, john).
likes(david,bertrand).
А все утверждения, включающие bertrand выбираются следующим образом:
* type likes / 2 CL (bertrand)
likes(bertrand, john).
likes(david,bertrand).
likes(john,ANYBODY):- likes(ANYBODY,bertrand).
Получение альтернативных решений для целевого утверждения осуществляется немного иначе, чем в Прологе-10:
*?- likes(john,Who).
WHO = alfred Continue (y/n)?
* y
WHO = david Continue (y/n)?
* у
NO
Новые утверждения можно добавлять как с помощью команды enter, так и путем чтения псевдо-файла user (как в Прологе-10):
*?- [user].
likes(timothy,bertrand).
likes/2+6
* bye
Yes
Команда ввода вопроса (?-) не выдает сведений о времени его выполнения. Эту информацию можно получить путем задания команды execute (в краткой форме ':'):
* :likes(john,X).
(*** CPU time: 0.27 sec, 1 calls, 0 backtracks ***)
Подсистема PDSS гибко реагирует на синтаксические ошибки. В стандартном режиме при возникновении такой ошибки пользователю предоставляется выбор: отредактировать ошибочное утверждение или выполнить целевое утверждение:
*?- likes(john,ann)). full stop expected at) Enter the editor (y/n)?
* y
10: likes(john,ann))
*** Enter editor commands
* 10: likes(john,ann)
*** Line 10 replaced ***
* end NO
Команда end закрывает цикл редактирования. Затем делается попытка согласовать отредактированную цель, и в результате получается ответ NO.
Тот же метод применим и в случае чтения файла в базу данных: ошибочные утверждения могут быть отредактированы, а затем процесс чтения файла продолжается.
Сеанс работы с PDSS завершается по команде bye. При этом система предупреждает пользователя о возможности утраты модулей, которые не были записаны в файлы.
* bye
*** The following module(s) have not been saved: ***
first Do you want to exit (y/n)?
* y
Normal exit from MPROLOG PDSS
Синтаксис
Синтаксис МПролога в основном совместим с синтаксисом Пролога-10. Правда, позиции операторов, их приоритеты и ассоциативность в МПрологе отличаются, однако, для обеспечения совместимости с тем, что описано в данной книге, предусмотрен встроенный предикат ор. Списки можно задавать как с помощью точечной записи (используя для этого предварительно описанный оператор '.'), так и с помощью скобочной записи [].
Строки в МПрологе не эквивалентны списку кодов, составляющих их литер. Это означает, что пример из гл. 5 (база данных исторических событий) с вопросом событие(1524,Х) будет работать и ответом будет 'Васко да Гама умер'.
Модульность
В самом языке и в системе разработки программ предусмотрены средства модульного построения программ. МПролог-программа может состоять из нескольких модулей, которые взаимодействуют между собой только через заданные интерфейсы модулей.
Например, предикат найти для работы со словарем, имеющим вид упорядоченного дерева (см. разд. 7.1), может быть заключен в такой модуль:
module dictionary.
export (найти / 3, печ_дерево / 3).
import (меньше / 2).
visible (таблица, подряд), body.
найти(Н, b(H,G,_,_), G):-!.
найти(Н, в(Н1,_,BEFORE,_),G):- меньше(Н,Н1)?найти(Н,ВЕFОRЕ,G).
найти(Н,в(Н1,,_,AFTER),G):- not(меньше(Н,Н1)), найти (H,AFTER,G).
печ_дерево(T,FORM,KEYWORD):- var(T),!.
печ_дерево(в(H,W,L,G),F,K):- печ_дерево(L,F,K), печ_элемент(Н,W,F,K), печ_дерево(G,F,K).
печ_элемент(Н,W,таблица,K):- !, outterm(H), outtab(15), outterm(K),outspaces(l), outterm(W), newline.
печ_элемент(Н,W,подряд,K):- outterm(H), outspaces(l), outterm(K), outspaces(1), outterm(W), outterm(",").
end mod /* dictionary */.
Этот модуль «экспортирует» (т. е. делает доступным для других модулей) предикаты найти/3 и печ_дерево/3, и только эти предикаты данного модуля могут быть использованы вне его. Предикат печ_дерево может выводить на печать заданное дерево в двух возможных форматах в соответствии с аргументом FORM, который может иметь значения таблица и подряд. Эти два имени описаны как видимые, что указывает на то, что они используются не только внутри данного модуля например, как конструктор в-структур. Видимость имени не обязательно обозначает сохранение его символьного представления в другом модуле, однако, если оно используется в другом модуле как видимое имя, то эти два вхождения унифицируются.
Заметим, что конкретное представление дерева скрыто в данном модуле.
Рассмотрим еще один модуль, использующий определенные выше предикаты. Предположим, что у нас есть список лошадей, участвующих в бегах, в порядке их финиширования, а нам нужно получить алфавитный перечень их кличек с указанием занятого места. Для этого можно воспользоваться предикатом печ_ индекс, который по списку кличек порождает дерево, а затем выводит его на печать.
module index.
export(печ_индекс/0).
import(найти/3, список_кличек/1, печ_дерево/3).
visible(таблица).
body.
печ_индекс:- список_кличек(L),созд_дерево(L, 1, Т, печ_дерево(Т,таблица,": ").
созд_дерево([],_,_):- !.
созд_дерево([NАМЕ|L,N,Т):- найти(NAME,T,N), M is N+1, созд_дерево(L,М,T).
endmod /* index */.
Здесь снова имя таблица задано как видимое, тогда как параметр KEYWORD предиката печ_дерево (здесь он имеет значение ".") заключен в двойные кавычки. Это означает, что символьное представление этого имени должно быть сохранено.
Компоненты системы МПролог
Ядром системы МПролог является интерпретатор. Другой основной компонентой системы является подсистема разработки программ PDSS, которая сама написана на МПрологе и работает под управлением интерпретатора. Подсистема PDSS обеспечивает возможности диалоговой разработки программ.
После того как фаза разработки программ закончена, можно воспользоваться тремя другими компонентами системы, обеспечивающими эффективность выполнения программы.
Претранслятор системы МПролог преобразует МПролог-модули во внутреннее представление, допускающее эффективное выполнение. Он обрабатывает элементы программы, осуществляя их оптимизацию, управляемую пользователем. Например, использование описаний вида match_order и mode позволяет значительно повысить эффективность поиска утверждений.
Второй компонентой системы является консолидатор, который объединяет двоичные модули в выполняемую программу. Объединение может осуществляться по шагам. Это означает, что несколько двоичных модулей можно объединить в один новый двоичный модуль с внешним интерфейсом, заданным пользователем.
Третьей из указанных выше компонент системы является компилятор, который преобразует двоичные модули (порождаемые претранслятором), заменяя представление программы, необходимое для интерпретатора, на непосредственно исполняемый машинный код. Система МПролог допускает объединение в готовую программу интерпретируемых и откомпилированных модулей.
Различные ограничения
Целые числа могут изменяться в диапазоне от -8 388 607 до 8 388 607. Действительные числа не предусмотрены. Приоритеты операторов могут изменяться от -3000 до 3000.
Дополнительные встроенные предикаты
В МПрологе предусмотрены некоторые дополнительные встроенные предикаты. Например, допускающие повторное согласование при возвратном ходе предикаты ввода, разнообразные предикаты вывода, работы со строками, с базой данных, а также предикаты обработки особых ситуаций.
Два основных предиката ввода insymb(X) и interm(X) допускают повторное согласование при возврате. Это означает, что при возвратном ходе выполненные ими действия «отменяются». Например, если первый вводимый символ не совпадает с аааа, то вопрос
? insymb(aaaa).
не согласуется, причем в этом случае аааа сохраняется во входном потоке и может быть считан последующими предикатами ввода[21].
Эти предикаты обеспечивают дополнительные возможности для задания грамматических правил. Например, правила, приведенные в разд. 9.3, могут быть непосредственно преобразованы в следующие предикаты: