В системе Prolog можно легко реализовать объектно-ориентированный стиль программирования. В данном разделе применение такого стиля демонстрируется на примере простого интерпретатора для объектно-ориентированных программ. При использовании объектно-ориентированного подхода программа рассматривается как состоящая из объектов, которые передают друг другу сообщения. Вычисление происходит в результате формирования объектом ответа на полученное сообщение. Каждый объект имеет собственную область памяти и некоторые процедуры, называемые методами. Кроме того, объекты могут наследовать методы от других объектов. Применяемый при этом механизм аналогичен механизму наследования в методе представления данных на основе фреймов (см. главу 15). Объект отвечает на сообщение, вызывая на выполнение один из своих методов, а сообщение определяет, какой метод должен быть выполнен. Действие по передаче сообщения объекту фактически представляет собой своего рода вызов процедуры. Реализация объектно-ориентированной программы по сути является моделированием процессов передачи сообщений между объектами и формирования объектами ответов на сообщения.
Чтобы ознакомиться с тем, как этот принцип практически осуществляется в системе Prolog, рассмотрим в качестве первого примера объектно-ориентированную программу, касающуюся геометрических фигур. Одним из объектов этой программы является прямоугольник, а в состав данного объекта могут входить процедуры для описания прямоугольника и вычисления его площади. Если объекту прямоугольника передается сообщение area (А), он отвечает, вычисляя площадь прямоугольника, и переменная А становится конкретизированной значением этой площади. В рассматриваемой реализации объект будет представлен как отношение object[ Object, Methods)
где Object — терм, который именует объект (и, возможно, задает его параметры), а Methods — список термов Prolog, определяющих методы. Термы в этом списке имеют форму предложений Prolog, т.е. обычных фактов и правил Prolog (если не считать того, что они не оканчиваются точкой). Б рассматриваемой реализации Prolog определение любого объекта может задавать целый класс объектов, таких как класс всех прямоугольников, определяемых с помощью предиката rectangle [ Length, Width). В таком случае конкретный прямоугольник со сторонами 4 и 3 определяется
Часть II. Применение языка Prolog в области искусственного интеллекта
с помощью терма rectanglet 4, 3). Это означает, что в общем объект rectangle { Length, Width] с двумя методами, area и describe, может быть определен следующим образом:
object! rectangle! Length, Width),
[(area(A):-A is Length * Width),
(describe:-write('Rectangle of size '), write(Length * Width)> ]).
В данной реализации процесс передачи сообщения объекту может быть промоделирован с помощью такой процедуры: send(Object, Message)
Для того чтобы объект прямоугольника со сторонами 4 и 3 описал себя и вычислил свою площадь, ему достаточно передать соответствующие сообщения:
?- Reel = rectangle; 4, 3}, send! Reel, describe), send! Reel, area(Area)). Rectangle of size 4*3 Area = 12
Составить программу для процедуры send{ Object, Message) можно достаточно просто. Вначале необходимо обеспечить выборку методов объекта Object. Эти методы фактически определяют программу Prolog, которая является локальной по отношению к Object. Затем нужно вызвать на выполнение эту программу, задав ей в качестве цели сообщение Message. Программа, представленная в виде списка, состоит из компонентов в форме Head: - Body или просто Head в случае, если тело является пустым. Чтобы выполнить программу с целью Message, требуется найти голову предложения, которая согласуется с целью Message, а затем выполнить соответствующее тело предложения с помощью собственного интерпретатора Prolog.
Прежде чем реализовать этот замысел в программе, необходимо рассмотреть еще один существенно важный механизм объектно-ориентированного программирования — наследование методов в соответствии с отношением "isa" (является) между объектами. Например, квадрат "isa" прямоугольником. Для вычисления его площади в объекте квадрата может использоваться такая же формула, как и в объектах, прямоугольников. Поэтому для квадрата не требуется его собственный метод area; он может унаследовать этот метод от класса прямоугольников. Для того чтобы получить такую возможность, необходимо определить объект square и дополнительно указать, что он также является прямоугольником.
object! sguare(Side), [ (describe:-
write! 'Square with, side '),
write(Side)) ]). isa(square(Side), rectangle[ Side, Side)).
Это дает возможность успешно выполнить следующий запрос:
?- send! square(5), area(Area)!. Дгег - 25
Сообщение area{ Area) обрабатывается таким образом: вначале выполняется поиск метода area (Area) среди методов объекта square (5), но найти его не удается. Затем с помощью отношения isa успешно выполняется поиск этого метода в суперобъекте квадрата - в прямоугольнике rectangle (5, 5). Суперобъект имеет соответствующий метод area, который вызывается на выполнение.
Интерпретатор для объектно-ориентированных программ, разработанный в соответствии с замыслом, описанным в данном разделе, приведен в листинге 23.5, а в листинге 23,& приведена законченная объектно-ориентированная программа, относящаяся к геометрическим фигурам.
Глава 23. Метапрограммирование
Листинг 23.5. Простой интерпретатор для объектно-ориентированных программ
' 1 Интерпретатор для объе к тно-оркентированных программ
4 send; Message, Object) если
Т требуется найти методы объекта Object и вызвать на выполнение метод,
i который соответствует сообщению Message
send; Object, Message):-
get_methods(Object, Methods), \ Найти методы объекта Object
process! Message, Methods). % Вызвать на выполнение соответствующий метод
get_methods(Object, Methods!:-
object! Object, Methods!. % Собственные методы
get_methods(Object, Methods):-
isa(Object, SuperObject),
getjmethads! SuperObject, Methods). % Унаследованные методы
process! Message, [Message I _]). % Использовать факт
process [ Message, [ (Message:- Body) I _]):- % Использовать правило call(Body),
process! Message, [_ I Methods]}:-process! Message, Methods).