
- •Введение
- •Система обозначений
- •Переменные
- •Функция bind
- •Глобальные переменные
- •Процедурные функции
- •Функция if
- •Функция while
- •Функция switch
- •Функция loop-for-count
- •Функция break
- •Функция halt
- •Конструкция deffunction
- •Функция return
- •Конструкция deftemplate
- •Упорядоченные факты
- •Атрибуты deftemplate
- •Правила
- •Значимость
- •Рабочий список правил и выполнение программы
- •Отображение рабочего списка правил
- •Команды, применяемые для манипулирования конструкциями
- •Команда printout
Упорядоченные факты
Факты с именем отношения, имеющие соответствующую конструкцию deftemplate, называются фактами с конструкцией deftemplate. С другой стороны, факты с именем отношения, не имеющие соответствующей конструкции deftemplate, называются упорядоченными фактами. Под этим подразумевается, что упорядоченные факты имеют единственный многозначный слот, используемый для хранения всех значений, следующих за именем отношения. В действительности при обнаружении интерпретатором CLIPS каждого упорядоченного факта автоматически создается подразумеваемая конструкция deftemplate для этого факта (в отличие от явной конструкции deftemplate, создаваемой с применением определения deftemplate). Любой упорядоченный факт имеет только один слот, поэтому при определении такого факта имя слота не требуется. Например, с помощью следующего факта может быть представлен список чисел:
(number-list 7 9 3 4 20)
По существу это определение эквивалентно определению такой конструкции deftemplate:
(deftemplate number-list (multislot values)) и последующему заданию факта таким образом:
(number-list (values 7 9 3 4 20))
Вообще говоря, при любой возможности следует использовать факты с конструкцией deftemplate, поскольку благодаря наличию имен слотов факты становятся более пригодными для чтения, а работа с ними облегчается. Тем не менее можно назвать два случая, в которых полезны и упорядоченные факты. Во-первых, факты, состоящие только из имени отношения, могут применяться в качестве флагов и выглядят одинаково, независимо от того, была для них определена конструкция deftemplate или нет. Например, следующий упорядоченный факт может использоваться в качестве флажка для указания на то, что все заказы обработаны:
(all-orders-processed)
Во-вторых, для факта, содержащего единственный слот, имя слота обычно становится синонимом имени отношения. Например, следующие факты:
(time 8:45)
(food-groups meat dairy bread fruits-and-vegetables)
несут в себе не меньше смысла, чем такие факты:
(time (value 8:45))
(food-groups (values meat dairy bread fruits-and-vegetables))
Все факты, известные системе CLIPS, группируются и сохраняются в списке фактов. Этот список фактов позволяет добавлять и удалять факты, представляющие информацию. Новые факты могут быть добавлены к списку фактов с использованием команды assert. Команда assert имеет следующий синтаксис:
(assert <fact>+)
В качестве примера воспользуемся конструкцией deftemplate с именем person для описания некоторых людей с помощью фактов. Информацию о человеке с именем John Q. Public можно добавить к списку фактов с помощью следующих команд:
CLIPS> (deftemplate person
(slot name)
(slot age)
(slot eye-color)
(slot hair-color))
CLIPS>(assert (person (name "John Q. Public")
(age 23)
(eye-color blue)
(hair-color black)))
<Fact-0>
CLIPS>
Обратите внимание на то, что команда assert возвращает значение, <Fact-0>. Для отображения фактов, находящихся в списке фактов, можно воспользоваться командой facts. Основной синтаксис команды facts является таковым:
(facts)
А ниже приведен пример применения этой команды.
CLIPS> (facts)
f-0 (person (name "John Q. Public") (age 23) (eye-color blue) (hair-color black))
For a total of 1 fact.
CLIPS>
Терм "f-0" представляет собой идентификатор факта, присвоенный этому факту системой CLIPS. Каждому факту, вставляемому в список фактов, присваивается уникальный идентификатор факта, начинающийся с буквы f и заканчивающийся целым числом, которое называется индексом факта. Индекс факта 0 был показан также в возвращаемом значении <Fact-0> показанной выше команды assert. При обычных обстоятельствах система CLIPS не допускает ввод дублирующихся фактов. Поэтому попытка поместить в список фактов второй факт "John Q. Public" с идентичными значениями слотов не приведет к значимому результату. Но, безусловно, к списку фактов можно легко добавлять другие факты, не являющиеся дубликатами существующих фактов, например, как показано ниже.
CLIPS> (assert (person (name "Jane Q. Public") (age 36)
(eye-color green) (hair-color red)))
<Fact-l>
CLIPS> (facts)
f-0 (person (name "John Q. Public") (age 23) (eye-color blue) (hair-color black))
f-1 (person (name "Jane Q. Public") (age 36) (eye-color green) (hair-color red))
For a total of 2 facts.
CLIPS>
Как показывает синтаксис команды assert, с помощью единственной команды assert можно ввести в систему несколько фактов одновременно. Например, следующая команда добавляет в список фактов сразу два факта:
(assert (person (name "John Q. Public")
(age 23)
(eye-color blue)
(hair-color black))
(person (name "Jane Q. Public")
(age 36)
(eye-color green)
(hair-color red)))
Важно помнить, что идентификаторы фактов в списке фактов не обязательно должны быть последовательными. Кроме того, факты можно не только добавлять к списку фактов, но и удалять из этого списка с помощью определенного способа. После удаления фактов из списка фактов идентификаторы удаленных фактов становятся пропущенными в списке фактов, поэтому в ходе выполнения программы CLIPS может быть нарушена строгая последовательность индексов фактов.
Количество фактов, содержащихся в списке фактов, может стать весьма значительным, поэтому часто желательно иметь возможность рассматривать только часть списка фактов. Такая возможность обеспечивается с помощью задания дополнительных параметров команды facts. Полный синтаксис команды facts приведен ниже:
(facts [<start> [<end> [<maximum>]]])
В этой команде в качестве параметров <start>, <end> и <maximum> применяются положительные целые числа. Следует отметить, что синтаксис команды facts допускает использование от нуля до трех параметров. Если параметры не заданы, отображаются все факты. Если задан параметр <start>, то отображаются все факты с индексами фактов, большими или равными значению <start>. Если заданы параметры <start> и <end>, отображаются все факты с индексами фактов, большими или равными значению <start> и меньшими или равными значению <end>. Наконец, если наряду с параметрами <start> и <end> задан параметр <maximum>, то отображается количество фактов, не превышающее значение <maximum>.
Еще раз отметим, что существует возможность не только добавлять, но и удалять факты из списка фактов. Удаление фактов из списка фактов называется извлечением и выполняется с помощью команды retract. Команда retract имеет следующий синтаксис:
(retract <fact-index>+)
В качестве параметров команды retract должны быть указаны индексы фактов, относящиеся к одному или нескольким фактам. Например, информацию о человеке по имени John Q. Public можно удалить из списка фактов с помощью такой команды:
(retract 0)
Аналогичным образом, следующая команда позволяет извлечь из списка фактов тот факт, который относится к Jane Q. Public:
(retract 1)
Попытка извлечь несуществующий факт приводит к получению следующего сообщения об ошибке (в этом сообщении ключ [PRNTUTIL1] представляет собой ключ для поиска описания данного сообщения об ошибке в справочном руководстве CLIPS Reference Manual):
[PRNTUTIL1] Unable to find fact <fact-identifier>.
В качестве примера можно указать такой фрагмент диалога системы: CLIPS> (retract 1)
CLIPS> (retract 1)
[PRNTUTIL1] Unable to find fact f-1.
CLIPS>
Единственная команда retract может использоваться для одновременного извлечения нескольких фактов. Например, следующая команда извлекает факты f-0 и f-1:
(retract 0 1)
Значения слотов фактов с конструкцией deftemplate могут модифицироваться с помощью команды modify. Синтаксис команды modify является таковым:
(modify <fact-index> <slot-modifier>+)
В этой команде параметр <slot-modifier> имеет следующий вид: (<slot-name> <slot-value>)
Например, после наступления очередного дня рождения лица по имени John Q. Public можно изменить его возраст с 23 на 24 с помощью такой команды modify:
CLIPS> (modify 0 (age 24))
<Fact-2>
CLIPS> (facts)
f-2 (person (name "John Q. Public") (age 24) (eye-color blue) (hair-color black))
For a total of 1 fact.
CLIPS>
Команда modify действует по принципу извлечения первоначального факта и последующего добавления нового факта после модификации указанных значений слотов. В связи с этим для модифицированного факта вырабатывается новый индекс факта.
Команда duplicate действует по такому же принципу, за исключением того, что извлечение первоначального факта не происходит. Таким образом, если найдется давно пропавший брат-близнец Джона, Джек, то информацию о нем можно будет добавить к списку фактов, продублировав факт с информацией о Джоне и изменив значение слота name, как показано ниже.
CLIPS> (duplicate 2 (name "Jack S. Public"))
<Fact-3>
CLIPS> (facts)
f-2 (person (name "John Q. Public") (age 24) (eye-color blue) (hair-color black))
f-3 (person (name "Jack S. Public") (age 24) (eye-color blue) (hair-color black))
For a total of 2 facts.
CLIPS>
Команды modify и duplicate не могут использоваться для работы с упорядоченными фактами.
Команда watch является полезным средством отладки программ. Команда watch имеет такой синтаксис:
(watch <watch-item>)
В этом определении <watch-item> обозначает один из символов facts, rules, activations, statistics, compilations, focus, deffunctions, globals, generic-functions, methods, instances, slots, messages, message-handlers или all.
Отслеживание этих элементов может осуществляться в любых комбинациях для получения необходимого объема отладочной информации. Команда watch может быть вызвана на выполнение несколько раз для отслеживания больше чем одного аспекта функционирования системы CLIPS. Чтобы разрешить отслеживание с помощью команды watch всех аспектов функционирования системы CLIPS, можно применить ключевое слово all. По умолчанию сразу после запуска системы CLIPS отслеживаются действия по компиляции, compilations, а остальные элементы команды watch не отслеживаются.
Если осуществляется отслеживание фактов с помощью символа facts, система CLIPS автоматически выводит сообщение, указывающее на то, что в списке фактов произошло некоторое обновление, при выполнении каждой операции вставки или удаления фактов. Применение этой команды отладки иллюстрируется в следующем командном диалоге:
CLIPS> (facts 3 3)
f-3 (person (name "Jack S. Public") (age 24) (eye-color blue) (hair-color black))
For a total of 1 fact. clips> (watch facts)
CLIPS> (modify 3 (age 25))
<== f-3 (person (name "Jack S. Public") (age 24) (eye-color blue) (hair-color black))
==> f-4 (person (name "Jack S. Public") (age 25) (eye-color blue) (hair-color black))
<Fact-4>
CLIPS>
Последовательность знаков <== указывает, что происходит извлечение факта, а последовательность знаков ==> указывает, что происходит добавление факта.
Существует возможность обеспечить отслеживание только конкретных фактов, указав одно или несколько имен конструкций deftemplate в конце команды watch. Например, выполнение команды (watch facts person) приводит к тому, что сообщения, касающиеся фактов, отображаются только применительно к факту person.
Отображение результатов, предусмотренных командой watch, можно отменить с использованием соответствующей команды unwatch. Команда unwatch имеет такой синтаксис: (unwatch <watch-item>)
Часто удобно иметь возможность автоматически вводить множество фактов, а не набирать похожие друг на друга команды в режиме работы верхнего уровня. Это особенно относится к тем фактам, которые заведомо являются истинными еще до выполнения программы (например, начальные знания). Еще одна ситуация, в которой удобно автоматически вводить группу фактов, относится к прогону тестовых наборов для отладки программы. Группы фактов, представляющих начальные знания, можно определить с помощью конструкции deffacts. Например, ниже приведен оператор deffacts, предоставляющий начальную информацию о некоторых лицах, которые уже упоминались в данной главе.
(deffacts people "Some people we know"
(person (name "John Q. Public")
(age 24)
(eye-color blue)
(hair-color black))
(person (name "Jack S. Public")
(age 24)
(eye-color blue)
(hair-color black))
(person (name "Jane Q. Public")
(age 36)
(eye-color green)
(hair-color red)))
Конструкция deffacts имеет следующий общий формат:
(deffacts <deffacts name> [<optional comment>] <facts>*)
Вслед за ключевым словом deffacts находится обязательное имя этой конструкции deffacts. В качестве имени может использоваться любой допустимый символ. В данном случае для конструкции выбрано имя people. За именем следует необязательный комментарий в двойных кавычках. Как и необязательный комментарии правила, этот комментарий сохраняется в определении конструкции deffacts после загрузки соответствующего определения системой CLIPS. Вслед за именем или комментарием находятся факты, которые вводятся в список фактов с помощью оператора deffacts.
Факты, заданные в операторе deffacts, вводятся с помощью команды reset языка CLIPS. Команда reset удаляет все факты из списка фактов, а затем вводит факты из существующего оператора deffacts. Синтаксис команды resetявляется таковым:
(reset)
Предположим, что введена конструкция deffactsc именем people (после конструкции deftemplate с именем person); в таком случае формируется следующий диалог, показывающий, как происходит ввод фактов в список фактов с помощью команды reset:
CLIPS> (unwatch facts)
CLIPS> (reset)
CLIPS> (facts)
f-0 (initial-fact)
f-1 (person (name "John Q. Public") (age 24) (eye-color blue) (hair-color black))
f-2 (person (name "Jack S. Public") (age 24) (eye-color blue) (hair-color black))
f-3 (person (name "Jane Q. Public") (age 36) (eye-color green) (hair-color red))
For a total of 4 facts.
CLIPS>
В этом выводе показаны факты из оператора deffacts и новый факт, выработанный командой reset, который имеет имя initial-fact. После запуска система CLIPS автоматически определяет следующие две конструкции:
(deftemplate initial-fact)
(deffacts initial-fact (initial-fact))
Таким образом, даже если в программе не определены какие-либо операторы deffacts, команда reset осуществляет ввод факта (initial-fact). Факт initial-fact всегда имеет идентификатор факта f-0. Польза от применения факта (initial-fact) заключается в том, что с него начинается выполнение программы (как описано в следующем разделе).