дб. Четвертое издание джозеф Джарратано Университет Хьюстон клиэрЛэйк Гари Райли People5oft, Издательский дом "Вильямс" Москва СанктПетербург Киев 2007 ббк 32. 973. 26 018 75 Д
Скачать 3.73 Mb.
|
(веаЬех$ р ?f:children) (printout t паше " is the mother of " ?instances, за исключением того, что в ней вначале отыскиваются все множества экземпляров, удовлетворяющие запросу, а затем выполняются указанные действия над всеми множествами экземпляров. В отличие от этого, при использовании функции do — for — all — instances запрос применяется к каждому множеству экземпляров, ив случае успешного выполнения проверки, предусмотренной в запросе, указанные действия применяются к полученному множеству экземпляров. Единственная ситуация, в которой эти функции вырабатывают разные результаты, возникает тогда, когда выполняемые действия изменяют результаты запроса в множестве экземпляров, которое еще не было обработано. Например, разные результаты применения этих двух функций могут быть вызваны изменением значения слота экземпляра, на который распространяется данный запрос 11.15. Множественное наследование Если ни одно множество экземпляров не удовлетворяет запросу, то возвращаемым значением всех функций запроса, допускающих применение действий, становится FALSE. В противном случае возвращаемым значением являются результаты последнего действия, выполненного над последним множеством экземпляров, удовлетворяющим запросу. Кроме того, функции запроса, допускающие применение действий, могут закончить свою работу преждевременно, если в них используются функция break или return. 11.15 Множественное наследование Во всех примерах применения конструкции de f class, которые рассматривались до сих пор в данной главе, в атрибуте is — а указан единственный класс. Все эти примеры характеризуются применением единичного наследования. Нов качестве значения атрибута is — а допускается задавать больше одного класса. В таком случае происходит так называемое множественное наследование. Нов тех случаях, когда указанные классы не имеют общих слотов или обработчиков сообщений множественное наследование по существу эквивалентно единичному наследованию, в котором используются суперклассы определяемого класса. Например, в следующем примере слоты х, у и z наследуются непосредственно от класса с применением множественного наследования CLIPS> (clear)J CLIPS> (defclass А (а USER) (slot z) ) J CLIPS> (defclass В (а) (8101 g))J CLIPS> (defclass С (а USER) (slot z) ) J CLIPS> (defclass D (а СВ х 3) (у 4) (z 5)) 1 fd1) CLIPS> (send [d1] print)J [d1] ой D 932 Глава 11 ° Классы, экземпляры и обработчики сообщений (х) (у 4) (z 5) CLIPS> В следующем примере классы В и С используются в промежуточных классах, чтобы обеспечить возможность косвенного наследования классом D слотов хи у по принципу единичного наследования CLIPS> (clear)J CLIPS> (defclass А (а USER) (slot x))J CLIPS> (defclass В (а Ау С (а В) (slot z) ) J CLIPS> (defclass D (is-а С)) J CLIPS> (make-instance [d1] of D (х 3) ус (х 3) (у 4) (z 5) CLIPS> Важно отметить, что в обоих случаях класс D наследует одни и те же слоты, но к классам В и С это не относится. Во втором примере существовала возможность переопределить классы В и С, поэтому мог быть достигнут тот же окончательный результат по созданию класса D с использованием единичного наследования вместо множественного наследования. Тем не менее множественное наследование применяется в тех ситуациях, когда имеются заранее заданные классы, которые невозможно модифицировать. Множественное наследование 933 Конфликты, связанные с множественным наследованием Большинство практических примеров использования множественного наследования относится к такой категории, что суперклассы, от которых производный класс наследует свои свойства, не имеют общих слотов или обработчиков сообщений (отличных от тех, которые унаследованы от класса USER). В подобных ситуациях между суперклассами не возникают конфликты, которые приходилось бы разрешать, а определяемые слоты и обработчики сообщений, которые конфликтуют со слотами и обработчиками сообщений суперкласса, перекрывают определения суперкласса также, как и при единичном наследовании. Рассмотрим краткий пример, в котором используется множественное наследование и обнаруживаются конфликтующие определения слотов и обработчиков сообщений в суперклассах: CLIPS> (clear)J CLIPS> (defclass А ах у (default 4))) 1 CLIPS> (defmessage-handler Ау В ау В compute () (+ 28е12:у 3)) ) CLIPS> (defclass С (а А В) 1 CLIPS> (defclass D (а В А) 1 CLIPS> В этом примере классы Си непосредственно наследуют свои свойства от классов Аи В. Нов классах Аи В имеются конфликтующие определения слота у и обработчика сообщений compute, поэтому рассмотрим, как разрешается этот конфликт CLIPS> (make-instance [ci] of C)J [c1] CLIPS> (make- instance [d|] of D)J 934 Глава 11. Классы, экземпляры и обработчики сообщений CLIPS> (send [c1] print)J [c1] of С (z 5) (х 3) (у 4) CLIPS> (send [d1] print)J [d1] й D (х 3) (у 1) (z 5) CLIPS> Анализ показанных результирующих значений слотов, относящихся к экземплярам [с1] и [c2], позволяет сделать два замечания. Первое из них касается порядка, в котором происходит вывод значений слотов, а второе касается значения слота у. Порядок, в котором выводятся значения слотов, не играет особой роли и просто показывает, что на результирующее определение класса оказывает некоторое влияние та последовательность, в которой имена суперклассов перечислены в атрибуте а. Более существенное различие между двумя экземплярами состоит в том, что заданное по умолчанию значение слота у для экземпляра [c1] равно 4, тогда как заданное по умолчанию значение слота у для экземпляра [d1] равно 1. Поскольку класс С вначале наследует свои свойства от класса А, тов нем используется значение слота у, заданное по умолчанию в классе А, а не значение, заданное по умолчанию в классе В. Аналогичным образом, класс D в первую очередь наследует свои свойства от класса В, поэтому в нем применяется значение слота у, заданное по умолчанию в классе Ване значение, заданное по умолчанию в классе А. Аналогичные действия осуществляются при определении обработчика сообщений compute: CLIPS> (send [c1] у 3) 3 CLIPS> (send [61] ри1.-у 3) 3 CLIPS> (send [c1] compute)J 30 CLIPS> (send [d1] compute)J б CLIPS> Даже несмотря на то, что слоту у в обоих экземплярах присвоено значение 3, результат обработки сообщения compute для экземпляра с равен 30, те. (3 * 10), а результат для экземпляра [d1] равен б, те. (3+ 3). Еще раз от 11 15. Множественное наследование метим, что причина этого состоит в том, что в экземпляре [c1] используется обработчик сообщений compute для класса А, а в экземпляре — обработчик сообщений compute для класса В. В тех простых случаях, в которых классы, заданные в атрибуте is — а, не имеют общих определяемых пользователем суперклассов, приоритет, используемый при наличии нескольких определений одного итого же слота или обработчика сообщений, определяется последовательностью задания классов в указанном атрибуте. В данном примере определения класса А имеют более высокий приоритет, чем определения класса В вовремя обработки объявления класса С, поскольку А указан перед В. А в классе D определения класса В имеют более высокий приоритет над определениями класса А, поскольку В был задан перед A. Задачу изучения более сложных случаев применения множественного наследования оставляем читателю. Полное описание проблематики множественного наследования наряду с примерами того, как происходит разрешение конфликтов, связанных с множественным наследованием во всех ситуациях, приведено в документе Basic Programming Guide, который находится на компакт-диске, прилагаемом к данной книге. Нов качестве общего принципа следует указать, что если в программе создаются классы с использованием множественного наследования и оттого порядка, в котором заданы классы в атрибуте is — а, зависит поведение определяемого класса, то можно предположить, что в программе применяется более сложное решение рассматриваемой проблемы, чем могло бы быть. Сохранение и восстановление значений слотов Рассмотрим практический пример применения множественного наследования определение класса RESTORABLE, который может использоваться с другими классами для сохранения и восстановления значений слотов экземпляра. Для реализации этого класса необходимо определить еще один класс, который будет служить для хранения значений слотов (defclass SAVED- SLOT (а USER) (slot slot-name) (multislot slot-value)) Класс — SLOT имеет слоты slot — name и slot — value. Слот пате используется для хранения имени сохраненного слота, а слот slot — value применяется для хранения значения указанного слота. Он определен как многозначный слот, поскольку необходимо предусмотреть возможность хранения значений слотов, полученных как из однозначных, таки из многозначных слотов. Класс RESTORABLE определен следующим образом Глава 11. Классы, экземпляры и обработчики сообщений RESTORABLE (is — а USER) (multislot Многозначный слот saved — slots предназначен для хранения от нуля и больше ссылок на экземпляры SAVED — представляющие значения сохраненных слотов экземпляра. Для сохранения значений слотов экземпляра используется следующий обработчик сообщений save: (defmessage-handler RESTORABLE save () Удалить существующие сохраненные слоты (progn$ (?si ?self:saved-slots) (send ?si delete)) (bind ?self:saved-slots) Составить список слотов ?class (class ?self)) (bind ?slots (delete-member$ (class-slots ?class inherit) saved — slots)) Создать пустой список (bind ?list (create$)) Обработать в цикле каждый слот (progn$ (?slot ?slots) (bind ?value (send ?self (sym-cat get- ?slot))) (bind ?ins (make- instance of SAVED-SLOT (пате ?slot) (slot-value ?value))) (bind ?list (create$ ?list ?ins))) Записать сохраненные слоты в паыять (bind ?self:saved-slots ?list)) Первое действие, выполняемое обработчиком сообщений save, состоит в том, что он удаляет все экземпляры SAVED — SLOT, хранимые в слоте saved — slots, на которые имеются ссылки. Затем слот saved — slots связывается с пустым многозначным значением. После этого формируется список слотов, подлежащих сохранению. Для определения имени класса данного экземпляра вызывается функция class. Затем имя класса передается в функцию class- slots наряду с ключевым словом inherit для получения многозначного списка, содержащего все имена слотов, связанные сданным классом. Наконец, имя слота saved-slots удаляется из этого списка с помощью вызова функции delete- member$. Этот слот не должен применять. Множественное наследование 937 ся для сохранения рассматриваемых значений, поскольку он предназначен для использования в качестве области памяти для значений всех других слотов. После этого создается пустой список, который должен содержать экземпляры SAVED — SLOT. Для обработки в цикле всех слотов сохраняемого экземпляра используется функция progn$. Прежде всего осуществляется выборка значения слота. Имя слота добавляется к символу get — для создания соответствующего сообщения, передаваемого экземпляру в целях выборки значения слота. Вслед за выборкой значения слота создается экземпляр SAVED — содержащий имя и значение слота. Ссылка на этот экземпляр добавляется к списку сохраненных слотов. А после обработки всех слотов список ссылок на экземпляры SAVED — сохраняется в слоте saved — slots. Теперь, после того как определен обработчик сообщений save, можно воспользоваться следующим обработчиком сообщений restore для выборки значений слотов экземпляра (defmessage-handler RESTORABLE restore () (progn$ (?si ?self:saved-slots) (bind ?name (send ?si get- slot-name)) (bind ?value (send ?si get-slot-value)) (send ?self (яутп- cat put- ?name) ?value))) Обработчик сообщений restore обрабатывает в цикле все экземпляры SAVED-SLOT, хранимые в слоте saved — slots. Из экземпляра SAVED — SLOT вначале осуществляется выборка имении значения каждого сохраненного слота. Имя слота добавляется к символу put для создания соответствующего сообщения, предназначенного для передачи экземпляру в целях присваивания значения слота. Затем это сообщение передается экземпляру для восстановления сохраненного значения в качестве значения слота. Теперь, после определения класса рассмотрим, как можно было бы его использовать вместе с существующим классом для создания нового класса, обладающего функциональными возможностями сохранения и восстановления. Для этого воспользуемся классом аналогичным рассматриваемому в предыдущих примерах PERSON (is — а USER) (slot full-name) (slot gender) (multislot children)) Определим следующий класс RESTORABLE — PERSON, который наследует свои свойства от обоих классов и PERSON: 938 Глава 11. Классы, экземпляры и обработчики сообщений RESTORABLE-PERSON (а RESTORABLE Для ознакомления стем, как реализуются функциональные возможности сохранения и восстановления, вначале необходимо создать экземпляр класса RESTORABLE — INSTANCE: CLIPS> (reset)J CLIPS> (make-instance р of RESTORABLE-PERSON (паве "Sue Jones" ) (gender female) (children Bob Jan))J [pl] CLIPS> (send р print)J [pl] of RESTORABLE-PERSON (пате "Sue 7опея") (gender female) (children Bob Jan) (saved-slots) CLIPS> После передачи экземпляру р ] сообщения save сохраняются текущие значения его слотов CLIPS> (send р save)J ([genl] [gen2] [депЗ]) CLIPS> (send р print)J [pl] of RESTORABLE — PERSON (пате "Sue Jones" ) (gender female) (children Bob Jan) (saved-slots [genl] [gen2] [депЗ]) CLIPS> Экземпляры [genl], [gen2] и [депЗ] представляют собой экземпляры класса созданные для сохранения значений слотов экземпляра [р1]. Рассмотрим содержимое этих экземпляров, чтобы ознакомиться стем, как хранятся отдельные значения слотов CLIPS> (send [gen1] print)J [genl] of SAVED-SLOT (пате full-name) (slot-value "Sue Jones" ) CLIPS> (send [gen2] print)J 11.16. Конструкции de f clas s и de f module 939 [gen2] of SAVED — SLOT (slot ïàmå gender) (slot-value female) CLIPS> (send [gen3] print)J [депЗ] of SAVED-SLOT (пате children) (slot-value Bob Jan) CLIPS> После передачи экземпляру сообщения restore восстанавливаются первоначальные значения слотов CLIPS> (send р restore)J (Bob Jan) CLIPS> (send р print)J [p1] of RESTORABLE — PERSON (full-name "Sue Jones" ) (gender female) (children Bob Jan) (saved-slots [gen1] [gen2] [депЗ]) CLIPS> 11.16 Конструкции def class и defmodule Конструкции de f class могут импортироваться и экспортироваться модулями по такому же принципу, как и другие конструкции. Дело в том, что к конструкциям de f class также могут применяться описанные выше в данной книге Затем изменим некоторые значения слотов экземпляра р следующим образом CLIPS> (send р put-full- name "Sue Smith™)J "Sue Smith" CLIPS> (send р put-children Bob Jan Paul)J (Bob Jan Paul) CLIPS> (send р print)J [pl] of RESTORABLE-PERSON (пате "Sue Smith" ) (gender female) (children Bob Jan Paul) (saved-slots [gen1] [gen2] [депЗ]) CLIPS> Глава 11. Классы, экземпляры и обработчики сообщений операторы export и import, которые экспортируют или импортируют все конструкции. Кроме того, предусмотрена возможность явно указывать, какие конструкции должны быть экспортированы или импортированы, с использованием одного из следующих операторов defclass ?ALL) defclass ?NONE) defclass defclass ?ALL) defclass (import При импортировании или экспортировании класса импортируются или экспортируются также все связанные с ним конструкции defmessage — handler. Но импорт или экспорт только определенных обработчиков сообщений невозможен. Если в модуле не импортируется какая-то конструкция de f class из другого модуля, тов нем существует возможность создать собственное определение этого класса с помощью того же имени класса. Исключением из этого правила являются классы, заранее определенные в системе, которые являются видимыми во всех модулях и не могут быть переопределены, такие как класс USER. Безусловно, факты связаны стем модулем, в котором определены относящиеся к ним конструкции deftemplate, а экземпляры связаны стем модулем, в котором определены относящиеся к ним конструкции de f class. Тем не менее каждый модуль имеет свое собственное "пространство имен, позволяющее обеспечить уникальность имен экземпляров. Это означает, что водном модуле не могут существовать два экземпляра, совместно использующие одно и тоже имя экземпляра, а в двух разных модулях могут присутствовать экземпляры, имеющие одинаковое имя экземпляра CLIPS> (defmodule А) CLIPS> (defclass а USER) (ezport defclass ?ALL)) 1 CLIPS> (make-instance [same] of ACLASS)J [same] CLIPS> (send [same] print)J [same] А CLIPS> (defmodule В CLIPS> (defclass В::BCLASS (is-а USER) (ezport defclass ИЛ )) CLIPS> (make-instance [same] of BCLASS)J [same] 11.16. Конструкции de f class и de fmodule 941 CLIPS> (send [same] print)J [same] of В CLIPS> (set-current-module А В CLIPS> (send ваше print)J [same] of А Обратите внимание на то, что определение экземпляра [same] в модуле Вне вызовет удаления экземпляра [ same ] в модуле А, как это обычно происходит, если в модуле А создается экземпляр стем же именем. Как показывает следующий пример, пространство имен экземпляров экспортирующего модуля не становится непосредственно видимым для импортирующего модуля CLIPS> (defmodule С (1прог A defclass ?ALL) (import В 7ALL))J CLIPS> (send [same] print)J [MSGPASS2] No such instance same in function send. FALSE CLIPS> В данном случае экземпляр [same] имеется ив модуле Аи в модуле В, но несмотря на это, в модуле С поиск указанного экземпляра осуществляется только в собственном пространстве имен экземпляров, поэтому данный экземпляр не обнаруживается. Один из способов, позволяющих сослаться на имя экземпляра в другом модуле, состоит в том, чтобы включить в состав имени экземпляра имя модуля и отделитель имени модуля, например, как показано ниже. CLIPS> (send А print) 1 [same] А CLIPS> (send В print)J [same] of В В данном случаев составе имени экземпляра было указано имя модуля, поэтому система CLIPS имеет информацию о том, какое пространство имен должно использоваться для поиска экземпляра, указанного по имени. Для поиска экземпляра, на который указывает имя экземпляра, может также применяться сам отделитель имени модуля, отдельно взятый (send [::same] print)J [same] of В Глава 11. Классы, экземпляры и обработчики сообщений 942 11.17 Загрузка и сохранение экземпляров В языке предусмотрено несколько команд, предназначенных для сохранения экземпляров в файлах и загрузки экземпляров из файлов по такому же принципу, как осуществляется сохранение и загрузка фактов. Этими командами являются save4nstàïñås, bsave4nstàïñås, load lïstànñås, restore lïstànñås и Иоана-1пйапсея. Указанные команды имеют следующий синтаксис (save-instances [[inherit] но на практике достаточно лишь иметь общее представление о том, как они действуют. Как правило, в программах ссылки на экземпляры создаются с применением адресов экземпляров, а не имен экземпляров. При использовании адресов экземпляров не возникает неоднозначность в отношении того, на какой экземпляр осуществляется ссылка, в отличие от тех ситуаций, когда применяются имена экземпляров. Дело в том, что имена экземпляров обычно используются при передаче сообщения экземпляру из приглашения к вводу команд и такие имена, вообще говоря, являются уникальными, поэтому если в текущем модуле импортируется конструкция сей, связанная с рассматриваемым экземпляром, то можно применять лишь отделитель имени модуля 11.17. Загрузка и сохранение экземпляров 943 струкцией def instances для определения экземпляров. Например, если файл "instances. dat" содержит информацию (Jack of PERSON (full- пате "Jack Q. Public" ) (age 23)) (of PERSON (пате "John Doe") (hair-color black)) то загрузку экземпляров, хранящихся в этом файле, обеспечит такая команда (load-instances "Вызов команды load — instances эквивалентен выполнению ряда вызовов команды make-instance. Команда restore — instances аналогична команде load — instances, нов ней не используются средства передачи сообщений при удалении, инициализации или определении значений слотов тех экземпляров, которые загружаются с ее помощью. Возвращаемым значением обеих этих команд является количество загруженных экземпляров или — 1, если при выполнении команды не удалось получить доступ к файлу экземпляров. Команда save — instances может использоваться для сохранения экземпляров в файле, указанном параметром — instances аналогичны командами, за исключением того, что для хранения экземпляров используется двоичный, а не текстовый формат. В связи с этим команда bload — instances может применяться только к файлам, сохраненным с помощью команды Преимуществом этих команд является то, что при наличии большого количества экземпляров загрузка в двоичном формате осуществляется быстрее, чем в текстовом формате. А их недостаток состоит в том, что двоичные файлы обычно не переносятся с одной компьютерной платформы на другую. Глава 11. Классы, экземпляры и обработчики сообщений 944 11.18 Резюме В настоящей главе приведено вводное описание языка COOL (CLIPS Object- Oriented Language — объектно- ориентированный язык CLIPS). Экземпляры (или объекты) служат в качестве еще одного способа представления данных, предусмотренного в языке CLIPS. Атрибуты экземпляра задаются с помощью конструкций de f class. С использованием конструкций de fmessage — handler с классами может быть связан процедурный код, оформленный в виде обработчиков сообщений. Механизм наследования позволяет использовать в классе слоты и обработчики сообщений, связанные с другим классом. Язык COOL поддерживает и единичное, и множественное наследование. Класс, который наследует свойства от другого класса, называется подклассом этого класса. Класс, от которого подкласс наследует свои свойства, называется суперклассом этого класса. Подкласс наследует от своих суперклассов атрибуты и обработчики сообщений, но при наличии в подклассе и суперклассе дублирующихся определений подкласс перекрывает определения суперкласса. С помощью атрибута role могут создаваться абстрактные классы, применяемые только для наследования. Экземпляры абстрактных классов не могут быть созданы. В отличие от этого, конкретные классы могут использоваться и для наследования, и для создания экземпляров этих классов. В языке COOL заранее определен целый ряд примитивных классов. Большинство классов, создаваемых пользователем, наследуют свои свойства от системного класса USER. Конструкция definstances позволяет создавать множество указанных экземпляров после выдачи команды reset. Кроме атрибутов слотов, предусмотренных в конструкции deftemplate, несколько дополнительных атрибутов слотов поддерживается также конструкцией сей. Атрибут source позволяет наследовать атрибуты слотов от суперклассов. Атрибут propagation дает возможность отменить наследование слота. Атрибут pattern — match позволяет указать, должен ли слот или класс участвовать в сопоставлении с шаблонами. Атрибут visibility позволяет управлять тем, может ли осуществляться непосредственный доступ к слоту со стороны обработчиков сообщений подклассов. Атрибут access непосредственно ограничивает разрешенный тип доступа к слоту. Атрибут create-accessor используется для управления автоматическим созданием обработчиков get — и put — для слотов класса. Атрибут storage позволяет указать, является ли значение слота совместно используемым всеми экземплярами класса, или каждый экземпляр имеет собственное значение этого слота. В системе CLIPS предоставляется несколько заранее определенных системных обработчиков сообщений, предназначенных для создания, инициализации, вывода на внешнее устройство и удаления экземпляров. Кроме того, могут быть также созданы обработчики сообщений, определяемые пользователем. Обработчики сообщений вызываются путем передачи экземпляру имени сообщения на Задачи Задачи 11.1. Модифицируйте программу, разработанную в результате решения задачи 10.3 (см. с. чтобы предусмотреть в ней возможности объяснения. После вывода информации о кустарнике, в наибольшей степени соответствующем требованиям пользователя, программа должна вывести приглашение для пользователя, чтобы он мог определить, желает ли он получить ряду с относящимися к сообщению параметрами с помощью команды send. Обработчик сообщений может относиться к одному из четырех типов, around, before или after. Обработчик типа primary обычно используется в качестве основного обработчика, предназначенного для формирования ответа на сообщение. Обработчики before и after вызываются соответственно дои после обработчика primary. Обработчик around именуется также обработчиком-оболочкой, поскольку он заключает в себе обработчики before, after и primary, выполняя свой код и дои после того, как выполняется код этих обработчиков. Обработчики around должны явно вызывать обработчики других типов. Обработчики сообщений primary перекрывают (или, как принято говорить, затеняют) обработчик сообщений primary для того же сообщения, унаследованного от суперкласса, хотя и предусмотрена возможность вызывать затененные обработчики. Но обработчики сообщений суперклассов around, йоге и ай1ег не затеняются определением подкласса. Сопоставление с шаблоном объекта предоставляет ряд возможностей, которые не могут обеспечиваться с помощью согласования с шаблоном фактов. Вопервых, единственный шаблон объекта может согласовываться с экземплярами нескольких классов. Во- вторых, изменения в значениях слотов, которые не заданы в шаблоне объекта, не приводят к повторной активизации правила, к которому принадлежит шаблон. В-третьих, изменения в значениях слотов, которые не заданы в шаблоне объекта в пределах условного элемента logical, не удаляют логическое обоснование, предусмотренное соответствующим правилом. В языке COOL предусмотрено несколько функций запроса множества экземпляров, которые позволяют непосредственно запрашивать множества экземпляров, отвечающих заданному множеству условий. Некоторые из этих функций позволяют также осуществлять определенные действия над результатами запросов. В ограничениях параметров для универсальных функций могут применяться определяемые пользователем классы, кроме предопределенных типов, предусмотренных в языке CLIPS. Для сохранения экземпляров в файле и загрузки экземпляров из файла могут использоваться функции save — instances, bsave-instances, load-instances, restore-instances и bloadinstances. 946 Глава 11. Классы, экземпляры и обработчики сообщений объяснение по поводу выбора указанного кустарника. Если будет нажата клавиша ввода, то программа должна остановиться. Если же будет введено название кустарника, то программа должна перечислить требования, которым он соответствует, требования, которым он не соответствует, а также другие требования, которым этот кустарник мог бы соответствовать. После вывода этого объяснения пользователю должен поступить еще один запрос, чтобы он мог указать, желает ли он получить объяснение по поводу кустарника другого вида. 11.2. Модифицируйте программу, разработанную в результате решения задачи (см. с. 846), таким образом, чтобы с ее помощью можно было составлять расписание для нескольких учащихся. Входные данные для программы должны считываться из файла. Вы вправе сами определять формат входных данных, но данные должны по меньшей мере включать имя каждого учащегося, названия предметов, которые должны быть включены в расписание, а также данные о том, какие преподаватели и какое время проведения занятий являются для учащегося более или менее предпочтительными. Выходные данные программы должны быть записаны в файл. Выходной файл должен содержать имя каждого учащегося, за которым следует расписание занятий по всем предметам для данного учащегося. 11.3. Модифицируйте программу, разработанную в результате решения задачи (см. с. 845), для демонстрации динамически реконфигурируемых меню. Например, предположим, что после выбора пункта меню 1 в субме- ню должны отображаться два пункта меню в субменю 2, а после выбора пункта меню 2 в субменю 1 — четыре пункта меню в субменю 2. 11.4. Применительно к следующей конструкции def class напишите обработчик для обработчика который должен запрашивать у пользователя значение слота side, если текущим значением является значение заданное по умолчанию (defclass SQUARE (а USER) (slot side (default unspecified))) 11.5. Создайте конструкцию de f class с именем ARRAY и связанные с ней обработчики сообщений, которые позволяют представить многомерный массив. Должны быть предусмотрены обработчики сообщений для получения и задания значений элементов массива. Кроме того, требуется также обеспечить возможность задавать применяемое по умолчанию значение для элементов массива и указывать начальное множество значений элементов массива в вызове make-instance, используемом для создания экземпляра Наконец, должен быть предусмотрен обработчик сообщений для отображения содержимого массива. Одномерные массивы должны отображаться Задачи 947 11.6. 11.7. 11.8. 11.9. в виде строки значений, а двумерные массивы — в виде таблицы, состоящей из строки столбцов. Массивы с более высоким количеством измерений должны отображаться с помощью листинга, в котором на каждой строке представлено одно значение, а этому значению предшествуют индексы. С использованием конструкции de f c1 as s с именем ARRAY и обработчиков сообщений, разработанных в результате решения задачи 11.5, перегрузите функцию * методом, который перемножает два двумерных массива. Применяйте дополнительные методы для проверки таких условий ошибки, как количество строки столбцов двух массивов, несовместимое для операции умножения массивов. Создайте конструкцию de f class с именем LINKED — LIST и соответствующие обработчики сообщений, которые позволяют создавать связные списки. Эта конструкция def class должна быть спроектирована таким образом, чтобы от нее могли наследовать свойства существующие классы для приобретения функциональных возможностей работы со связными списками. Необходимо предусмотреть обработчики сообщений, обеспечивающие выборку следующего и предыдущего объектов в списке, вставку объекта в список, удаление объекта из списка и вывод списка на внешнее устройство. Напишите программу, демонстрирующую использование конструкции de f c1 as s с именем LINKED-LIST на примере конструкции de f c1 as которая наследует от нее свойства, а также на примере другого класса. Создайте конструкцию defclass с именем ITERATOR и соответствующие обработчики сообщений, которые обеспечивают итеративную обработку полей многозначного значения. Значения, по которым осуществляется итерация, должны считываться и задаваться входе осуществления вызова make — instance, применяемого для создания экземпляра этого класса, ново всех остальных отношениях ни один из слотов данного класса не должен быть доступным, кроме как для обработчиков сообщений этого класса. Обработчик сообщений f irst должен быть предназначен для инициализации процесса итеративной обработки и возврата первого значения в списке итеративно обрабатываемых элементов. Обработчики сообщений next и previous должны соответственно обеспечивать выборку следующего или предыдущего значения в итеративном списке. Создайте конструкцию de f class с именем, которая обеспечивает хранение данных о значении длины и единицах измерения длины. Используя методы, разработанные в результате решения задачи, создайте новый метод, который складывает данные, представленные двумя экземплярами MEASUREMENT, и возвращает новый экземпляр, содержащий вычисленную сумму Глава 11. Классы, экземпляры и обработчики сообщений. Создайте конструкцию de f cl as s с именем STACK наряду с обработчиками сообщений, поддерживающими операции со стеком push (задвинуть) и рор (вытолкнуть. 11.11. Создайте конструкцию def class с именем SHUFFLER, которая реализует обработчик сообщений яЬийй1е (тасовать, обеспечивающий переупорядочение случайным образом списка значений, хранимого в экземпляре SHUFFLER. 11.12. Создайте конструкцию defclass с именем CARD для представления игральной карты. Создайте конструкцию defclass с именем которая инициализируется таким образом, чтобы в ней содержалась информация о колоде из 52 игральных карт. Предусмотрите обработчик сообщений shuffle, в котором используется конструкция defclass с именем разработанная в результате решения задачи 10.11, чтобы можно было сего помощью перетасовать колоду. 11.13. Перекройте функции —, * и / методами, которые обеспечивают выполнение операций вычитания, умножения и деление над экземплярами класса COMPLEX. 11.14. Напишите конструкцию def которая подсчитывает все вхождения каждого знака в строке и выводит итоговые данные о количестве обнаруженных знаков алфавита. 11.15. Создайте конструкцию de f class с именем, предназначенную для хранения имени номеров телефонов. Должны быть предусмотрены обработчики сообщений, позволяющие добавлять и удалять записи в этом телефонном справочнике, а также осуществлять поиск в справочнике по имени или по номеру и выводить все найденные записи Примеры проектов экспертных систем 12.1 Введение В настоящей главе приведено несколько примеров программ. Первый пример демонстрирует, как может быть представлена неопределенность в языке CLIPS. Следующие два примера показывают способы эмуляции других подходов к представлению знаний с использованием CLIPS. Водном из них показано, как можно представить в языке CLIPS деревья решений, а во втором продемонстрирован способ представления правил обратного логического вывода в языке. В четвертом и последнем примере создается инфраструктура простой экспертной системы, предназначенной для текущего контроля над показаниями группы датчиков. Коэффициенты достоверности В языке CLIPS непосредственно не предусмотрены какие-либо возможности учета неопределенности. Тем не менее в программу CLIPS несложно включить средства учета неопределенности, помещая информацию, касающуюся неопределенности, непосредственно в факты и правила. В качестве примера достаточно указать, что с помощью языка CLIPS может быть эмулирован механизм учета неопределенности, применяемый в системе MYCIN. В настоящем разделе будет показано, как можно перезаписать на языке CLIPS следующее правило MYCIN [25]: 950 Глава 12. Примеры проектов экспертных система THEN There is suggestive evidence (0.6) that the identity of the organism is pseudomonas В системе MYCIN фактическая информация представлена в виде троек "объект — атрибут — значение Attribute Value — OAV). Такие тройки OAV могут быть представлены в языке CLIPS с помощью следующей конструкции de f template (эта конструкция будет помещена в собственный модуль в целях создания повторно применимого программного компонента (defmodule OAV (export deftemplate oav)) (deftemplate OAV::oav (multislot object (type SYMBOL)) (multislot attribute (type SYMBOL)) (multislot value)) Эта конструкция de f template позволяет представить некоторые факты, требуемые для части IF приведенного выше правила, следующим образом (oav (object organism) (attribute stain) (value gramneg)) (oav (object organism) (attribute morphology) (value rod)) (oav (object patient) (attribute is а) (value compromised host)) Кроме того, в системе MYCIN с каждым фактом ассоциируется коэффициент достоверности (Certainty Factor — CF), который характеризует степень доверия к факту. Коэффициент достоверности может иметь значение от — 1 до значение — 1 показывает, что факт является заведомо ложным, значение Оговорит о том, что какая-либо информация об этом факте отсутствует (налицо полная неопределенность, а значение 1 свидетельствует, что факт является заведомо истинным. В системе CLIPS коэффициенты достоверности не учитываются автоматически, поэтому необходимо обеспечить сопровождение и данной информации. В этих целях в каждом факте будет использоваться дополнительный слот, представляющий коэффициент достоверности. После этого конструкция de f tempi ate с именем oav для каждого факта принимает такой вид. Коэффициенты достоверности 951 (deftemplate OAV::oav (multislot object (type ЯУМВО?)) (multislot attribute (type SYMBOL)) (multislot value) (slot CF (type FLOAT) (range — 1.0 +1.0))) В качестве примеров фактов можно привести следующее (oav (object organism) (attribute stain) (value gramneg) (CF 0.3)) (oav (object organism) (attribute morphology) (value rod) (CF 0.7)) (oav (object patient) (attribute is а) (value compromised host) (CF Для того чтобы факты oav функционировали должным образом, в программу на языке CLIPS необходимо внести еще одну модификацию. Система MYCIN позволяет осуществить логический вывод одних и тех же троек OAV с помощью отдельных правил. Затем эти тройки OAV комбинируются для получения единственной тройки OAV, в которой комбинируются коэффициенты достоверности исходных троек Применяемая в настоящее время конструкция deftemplate с именем oav позволяет вносить в список фактов две идентичные тройки OAV только в том случае, если в них имеются различные коэффициенты достоверности (поскольку система CLIPS в обычных условиях не позволяет вносить в список фактов два дублирующихся факта. Для того чтобы обеспечить возможность внесения в список фактов идентичных троек OAV, имеющих одинаковые коэффициенты достоверности, можно использовать команду яеФ4ас1-duplication для отмены применяемого в системе CLIPS принципа работы, согласно которому предотвращается внесение дублирующихся фактов в список фактов. Указанный принцип действия отменяется с помощью команды, имеющий следующий синтаксис (set-fact-duplication TRUE) Аналогичным образом, команда, имеющая следующую форму, исключает возможность внесения в список фактов дублирующихся фактов (set-fact-duplication FALSE) Как уже было сказано, в системе MYCIN две идентичные тройки комбинируются в одну тройку OAV, имеющую комбинированное значение коэффициента достоверности. Для вычисления нового коэффициента достоверности в системе Глава 12. Примеры проектов экспертных систем New Certainty = (СР1 + CFq) — (СР1 * CFq) Например, предположим, что в списке фактов имеются следующие факты (oav (object organism) (attribute morphology) (value rod) (CF 0.7)) (oav (object organism) (attribute morphology) (value rod) (CF 0.5)) Допустим, что СР1 обозначает коэффициент достоверности первого факта, равный 0.7, а CF — коэффициент достоверности второго факта, равный 0.5; в таком случае новый коэффициент достоверности для комбинации этих двух фактов вычисляется таким образом New Certainty = (0.7+ 0.5) — (0.7 * 0.5) = 1.2 — 0.35 = 0.85 а новый факт, заменяющий два первоначальных факта, принимает следующий вид (oav (object organism) (attribute morphology) (value rod) (CF 0.85)) Как уже было сказано, система CLIPS не обрабатывает автоматически коэффициенты достоверности, относящиеся к фактам из этого следует, что также не комбинирует автоматически две тройки полученные с помощью разных правил. Но комбинирование троек OAV можно легко обеспечить с помощью правила, которое осуществляет поиск в списке фактов идентичных троек подлежащих комбинированию. Ниже показано правило и описан метод, которые демонстрируют, как осуществляются указанные действия применительно к таким попарно обрабатываемым тройкам OAV, в которых коэффициенты достоверности больше или равны нулю. (defmethod OAV::combine-certainties ((?C1 |