Технический проект RBS-модуля

в этом разделе мы поговорим о том, как инициализировать RBS-модуль из файла данных, а также об интерфейсе, с помощью которого основной код системы ИИ будет взаимодействовать с этим модулем.
Инициализация
Как уже говорилось в главе 4, "FEAR: платформа для экспериментов", настройка модулей платформы FEAR выполняется на основе языка XML. В частности, в случае RBS-модуля этот подход позволяет получить гибкое и расширяемое описание системы. Таким образом, продумав как следует архитектурную и техническую части проекта модуля, мы легко поймем, как реализовать его в виде программного кода.
Рабочая память
Как уже говорилось в главе 11, "Системы, основанные на правилах", рабочая память RBS-системы — это, по сути, символы, которые в ней хранятся. В начальном состоянии рабочая память содержит все символы, которым присвоены значения, установленные по умолчанию (за исключением, естественно, тех символов, которым явно заданы начальные значения). В листинге 12.1 приведен пример рабочей памяти RBS-системы, содержащий два символа, sideWall и following. Эти символы говорят о наличии стены сбоку от анимата и о необходимости отслеживать контекст, соответственно. (Обратите внимание на то, что символам присвоены как значения, используемые по умолчанию, так и начальные значения.)
Код на языке XML, описывающий организацию рабочей памяти с двумя символами
/>
initial="true" defaults"false" />

Хотя символы объявляются одинаково, они тем не менее могут относиться к одному из двух разных типов. Внутренние (internal) символы используются только внутри RBS-системы (например, символ following). Внешние (native) символы соответствуют сенсорам или эффекторам, находящимся вне RBS-системы (например, lef twall). Это позволяет нам организовать неявное управление функциональными расширениями путем автоматической установки внешних символов до начала очередного цикла интерпретатора.
База правил
База правил состоит из простого набора рабочих правил, определяемых в виде пар "условие-операция". Условия (conditions) должны соответствовать символам, находящимся в рабочей памяти. Операции (action) также могут устанавливать символы, хотя в нашем случае, как уже отмечалось, система поддерживает процедурные сенсоры, которые не объявляются в явной форме.
Простая база правил на языке XML. содержащая только одно правило, разделенное на условия и операции

Отдельное условие правила представляет собой конъюнкцию атомарных операторов. Иными словами, оператор AND объединяет в виде единого условия отдельные символы, между которыми имеется неявное соответствие. Условия такого типа являются наиболее распространенными. Во всяком случае в рассматриваемой задаче нет необходимости прибегать к использованию операторов OR: в тех случаях, когда нам понадобится использовать дизъюнкцию (OR), мы вполне можем разбить условие на два. Такую работу можно выполнить как вручную (например, это может сделать инженер по представлению знаний), так и автоматически (с помощью специального программного инструмента).
Интерфейс
Интерфейс должен обеспечивать передачу данных в модуль во время выполнения программного кода. Для этого нужно сообщить системе, где хранится информация о внешних символах и как запускать соответствующие внешние операции. Тем самым будет обеспечиваться синхронизация данных, считываемых во время выполнения, со статическими объявлениями. В особых случаях можно также обеспечить возможность динамического расширения системы: например, позволить установку или получение значений символов либо добавление новых правил.
Синхронизация
Переменные можно регистрировать в модуле, передавая последнему указатели на них (первый параметр), а также их имена (второй параметр). Имя необходимо для того, чтобы обеспечить соответствие объявлениям переменных на языке XML.
SetSensor{ &SensorSideWall, "sideWall" );
Процедурные операции мы будем реализовывать в виде так называемых функторов (functor — классы, которые представляют собой хранилища функций ), поскольку они создают удобный механизм для реализации на языке C++ функций обратного вызова (callback function). Конечно, мы могли бы реализовать каждую операцию в виде отдельного класса, а затем просто перекрывать один метод, например Step (). При таком подходе RBS-система, когда ей нужно применить соответствующую операцию, просто вызывала бы эту виртуальную функцию. Однако использовать функторы удобнее, поскольку в этом случае каждой операции соответствует отдельный метод одного и того же класса. Кроме того, в этот же класс мы можем поместить внешние переменные, что также удобно с точки зрения реализации. (Как исходный код функтора выглядит на практике, лучше всего понять, изучая соответствующий практический пример.)