Листинг 23.6. Объектно-ориентированная программа, относящаяся к геометрическим фигурам
/* polygon! [Sidel, Side2, ...])
/ \
/ \
rectsngiet Length, Width) reg oolygocl Side, N)
\ / \
\ / \
souaref Side) pentagon! Sidei */
object! polygon! sides) , [ ( perimeter) P) :-
gum(Sides, P> ) ] ) .
object; reg_polygon[ Side, Ы) , [ ( perimeter! F) :.-E is Side * N) , ( describe :- write! 'Regular polygon') ) ] ).
object! sguare! Side) , [ ( describe :-
write! 'Sguare with side ' ) , write [ Side) ) 3 ) •
object; rectangle! Length, Width) , [ ( area{ A) :-
A is Length * Width) , ( describe :-
write! 'Rectangleof size ' ) , write! Length * Width) ) ] ).
object! pentagon! Side) ,
[ ( describe :- write! 'Pentagon') ) ] ).
isa( sguare! Side) , rectangle! Side, Side)) .
isa( sguare! Side! , reg_polygon [ .Side, 4) ) .
Часть It. Применение языка Prolog в области искусственного интеллекта
isal rectangle! Length, Widllh) , polygon! 5LengthrWidthFLength,Width])) .
j.sat pentagon [ Side), reg_polygon [ Side, 5)).
isal reg_polygon( Side, M), polygon)L!) :-
raafcelist[ Side, N, L) .
% makelistl item, И, List; если
i List - это список, в котором элемент Item появляется Краз
makelistl_, 0, []) .
makelist(Item, N, [Item ! List]) :-N > 0, N1 is N - 1, makeiistl item, HI, List).
& suml ListOfNumbers , Sum)если 'i Sum - это сумма чисел в списке ListofNumbers
sura ( [ ] , 0) ,
5шп( [Number | Numbers] , Sum) :-sum[ Numbers, SumlJ, Sum is Suml + Number,
До сих пор мы еще не упоминали о проблеме множественного наследования. Подобная проблема возникает, если отношение isa определяет такую решетку связей между объектами, что некоторые объекты имеют больше одного родительского объекта, как, например, объект square (см, листинг 23.6). Поэтому существует вероятность того, что некоторый метод может быть унаследован объектом больше чем от одного родительского объекта. В таком случае необходимо найти ответ на вопрос о том, какой из нескольких потенциально наследуемых методов должен использоваться в дочернем объекте. В программе, приведенной в листинге 23.5, предусмотрен поиск одного из применимых методов среди объектов в графе, определяемым отношением isa. В листинге 23.5 применяется простая стратегия поиска в глубину, но более подходящими могут оказаться некоторые другие стратегии. Например, поиск в ширину гарантирует, что будет всегда использоваться "ближайший наследуемый" метод.
В качестве дополнительной иллюстрации стиля объектно-ориентированного программирования, который поддерживается интерпретатором, приведенным в листинге 23.5, рассмотрим ситуацию, показанную на рис. 23.1. На этом рисунке изображен мир робота: определенное количество блоков, расставленных на столе в виде столбиков. На потолке установлена телекамера, которая снимает вид сверху объектов, находящихся на столе. Для простоты предположим, что все блоки представляют собой кубики со сторонами, равными 1. Блоки имеют имена а, Ь, .... а камера позволяет распознавать по именам те блоки, которые не закрыты сверху, и определять их координаты по отношению к осям к и у. Предположим, что перед нами стоит задача определения местонахождения объектов, т.е. их координат х, у и z. С каждым блоком связана некоторая локальная информация, поэтому известно, какой блок (если он существует) находится непосредственно над ним или под ним. Поэтому координаты х - у произвольного блока В могут быть получены одним из двух способов, описанных ниже.
1, Если блок не закрыт сверху другим блоком, то он может быть обнаружен с
помощью камеры, которая определит координаты х. - у этого блока. Такая
задача решается путем передачи камере сообщения look ( В, X, Y).
2. Если блок В расположен под некоторым блоком В1, то он находится вместе с
ним в одном и том же столбике, а все блоки одного столбика имеют одинако
вые координаты х - у. Поэтому, чтобы определить координаты х - у блока
В, необходимо отправить сообщение xy_coord( X, Y) блоку В1.
Глава 23. Метапрограммирование 573
I Телекамера
4-
ь
х Рис. 23.1. Мир робота
Аналогичные рассуждения позволяют найти способ определения координаты z любого блока. Если некоторый блок В стоит на столе, то его координата z равна 0, в. если В стоит на другом блоке В1, то достаточно передать сообщение z_coord( Z1) блоку Б1 и сложить полученную высоту Z1 с высотой В1, определив тем самым значение координаты 2 блока В. Такие операции выполняются в программе, приведенной в листинге 23.7, где блоки а, Ы т.д. определены как экземпляры класса блоков block ( BlockName), от которого они наследуют методы xycoord и z_coo!:d.