Прологовские программы как системы, управляемые образцами



 

Программы, написанные на Прологе, можно рассматривать как системы, управляемые образцами. Между пролог-программами и этими системами можно установить соответствие примерно следующим образом:

• Каждое предложение прологовской программы можно считать отдельным модулем со своим пусковым образцом. Голова предложения соответствует образцу, тело - тому действию, которое выполняет модуль.

• База данных системы — это текущий список целей, которые пролог-система пытается удовлетворить.

• Предложение пролог-системы "запускается", если его голова сопоставима с целью, расположенной первой в базе данных.

• Выполнить действие модуля (т.е. тело предложения) — это значит: поместить в базу данных вместо первой из целей весь список целей тела предложения (с соответствующей конкретизацией переменных).

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

 

Рис. 16.2. Основной цикл работы системы, управляемой образцами. В этом примере база данных согласуется с пусковыми образцами модулей 1, 3 и 4; для выполнения выбран модуль 3.

 

Пример составления программы

 

С системами, управляемыми образцами, связан свой особый стиль программирования, требующий специфического программистского мышления. Мы говорим в этом случае о программировании в терминах образцов .

В качестве иллюстрации, рассмотрим элементарное упражнение по программированию — вычисление наибольшего общего делителя D двух целых чисел А и В . Рассмотрим классический алгоритм Евклида:

 

Для того, чтобы вычислить наибольший общий делитель D чисел А и В , необходимо:

Повторять циклически, пока А и В не совпадут:

если А > В , то заменить А на А - В ,

иначе заменить В на В - А .

После выхода из цикла А и В совпадают; наибольший общий делитель D равен А (или В ).

 

Тот же самый процесс можно описать при помощи двух модулей, управляемых образцами:

Модуль 1

Условие В базе данных существуют такие два числа X и Y , что X > Y .

Действие Заменить X на разность X - Y .

Модуль 2

Условие В базе данных имеется число X .

Действие Выдать результат X и остановиться.

Очевидно, что всегда, когда условие Модуля 1 удовлетворяется, удовлетворяется также и условие Модуля 2, и мы имеем конфликт. В нашем случае конфликт можно разрешить при помощи простого управляющего правила: всегда отдавать предпочтение Модулю 1. База данных первоначально содержит числа А и В .

Здесь нас ждет приятный сюрприз: оказывается, что наша программа способна решать более общую задачу, а именно, она может вычислять наибольший общий делитель для любого количества чисел. Если в базу данных загрузить несколько целых чисел, то программа выведет их наибольший общий делитель. На рис. 16.3 показана возможная последовательность изменений, которые претерпевает база данных прежде, чем будет получен результат. Обратите внимание на то, что предварительные условия модулей могут удовлетворяться одновременно в нескольких местах базы данных.

 

Рис. 16.3. Процесс вычисления наибольшего общего делителя множества чисел. Первоначально база данных содержит числа 25, 10, 15 и 30. Вертикальная стрелка соединяет число с его "заменителем". Конечное состояние базы данных: 5, 5, 5, 5.

В данной главе мы реализуем интерпретатор простого языка для описания систем, управляемых образцами, и проиллюстрируем на примерах дух программирования в терминах образцов.

 

 

Простой интерпретатор программ, управляемых образцами

 

Для описания модулей, управляемых образцами, мы применим следующую синтаксическую конструкцию:

ЧастьУсловия ---> ЧастьДействия

Часть условия представляет собой список условий:

[ Условие1, Условие2, Условие3, ...]

где Условие1, Условие2 и т.д. — обычные прологовские цели. Предварительное условие запуска модуля считается выполненным, если все цели, содержащиеся в списке, достигнуты. Часть действия — это список действий:

[ Действие1, Действие2, ...]

Каждое отдельное действие — это, как и раньше, прологовская цель. Для того, чтобы выполнить список действий, нужно выполнить все действия из списка. Другими словами, все соответствующие цели должны быть удовлетворены. Среди допустимых действий будут действия, соответствующие манипулированию базой данных: добавить, удалить или заменить те или иные объекты базы данных.

На рис. 16.4 показано, как выглядит наша программа вычисления наибольшего общего делителя, записанная в соответствии с введенным нами синтаксисом.

 

% Продукционные правила для нахождения наибольшего общего

% делителя (алгоритм Евклида)

:- op( 300, fx, число).

 

[ число X, число Y, X > Y ] --->

[ НовХ is X - Y, заменить( число X, число НовХ) ].

[ число X ] ---> [ write( X), стоп ].

 

% Начальное состояние базы данных

число 25.

число 10.

число 15.

число 30.

Рис. 16.4. Программа, управляемая образцами, для получения наибольшего общего делителя множества чисел.

 

Самый простой способ реализации этого языка — использовать механизмы управления базой данных, встроенные в Пролог. Добавить объект в базу данных или удалить объект из базы данных можно, применяя встроенные процедуры

assert ( Объект) retract( Объект)

Заменить один объект на другой также просто:

заменить( Объект1, Объект2) :-

retract( Объект1), !,

assert( Объект2).

Здесь задача оператора отсечения — не допустить, чтобы оператор retract удалил из базы данных более чем один объект (при возвратах).

 

% Простой интерпретатор для программ, управляемых образцами

% Работа с базой данных производится при помощи процедур

% assert и retract

 

:- op( 800, xfx, --->).

 

пуск :-

Условие ---> Действие, % правило

проверить( Условие), % Условие выполнено?

выполнить( Действие).

 

проверить( []). % Пустое условие

проверить( [Усл | Остальные]) :- % проверить конъюнкцию

call( Усл), % условий

проверить( Остальные).

 

выполнить( [ стоп] ) :- !. % Прекратить выполнение

выполнить( []) :- % Пустое действие (цикл завершен)

пуск. % Перейти к следующему циклу

выполнить [Д | Остальные] ) :-

саll( Д),

выполнить( Остальные).

 

заменить( А, В) :- % Заменить в базе данных А на В

retract( A), !,

assert( В).

Рис. 16.5. Простой интерпретатор для программ, управляемых образцами.

 

Простой интерпретатор для программ, управляемых образцами, показан на рис. 16.5. Следует признать, что в интерпретаторе допущены значительные упрощения. Так, например, в него заложено чрезвычайно простое и жесткое правило разрешения конфликтов: всегда запускать первый из потенциально активных модулей (в соответствии с тем порядком, в котором модули записаны в программе). Таким образом, программисту предоставлено единственное средство управления процессом интерпретации — он может указать тот или иной порядок следования модулей. Начальное состояние базы данных задается в виде прологовских предложений, записанных в исходной программе. Запуск программы производится при помощи вопроса

?- пуск.

 


Дата добавления: 2018-05-01; просмотров: 365; Мы поможем в написании вашей работы!

Поделиться с друзьями:






Мы поможем в написании ваших работ!