5. Working Memory
Jess maintains a collection of knowledge nuggets called facts. This collection is known as the working memory. The most important thing to know about working memory is that rules can only react to additions, deletions, and changes to working memory. You can't write a Jess rule that will react to anything else. Working memory is therefore very important.
The good news is that working memory can contain Java objects, so that you can write rules that react to them. Each such Java object will appear to be represented by a single fact, Still, your rules will only know about those Java objects that have been placed in working memory. This section of the manual explains how to do that.
Working memory is something like a relational database, especially in that the facts must have a specific structure. From Jess's perspective, every fact in working memory looks like a row in a relational table. It has a name, like the name of the relation, and it has a set of properties, like the columns. This is the same structure that JavaBeans -- plain old Java objects, or POJOs -- have. You can think of it either way. Every fact corresponds to a single instance of the jess.Fact class.
In Jess, there are three kinds of facts: unordered facts, definstance facts (which are really just a kind of unordered facts) and ordered facts. You'll learn about unordered and ordered facts in this chapter, and about definstance facts here.
5.1. Unordered factsIn object-oriented languages, objects have named fields in which data appears. Unordered facts offer this capability (although the fields are traditionally called slots.)
(person (name "Bob Smith") (age 34) (gender Male)) (automobile (make Ford) (model Explorer) (year 1999))
(deftemplate <deftemplate-name> [extends <classname>] [<doc-comment>] [(declare [(<declarand> <value>)]*)] [(slot <slot-name> [(default | default-dynamic <value>)] [(type <typespec>))]*)
Jess> (deftemplate automobile "A specific car." (slot make) (slot model) (slot year (type INTEGER)) (slot color (default white)))
Jess> (reset) Jess> (assert (automobile (make Chrysler) (model LeBaron) (year 1997))) <Fact-1> Jess> (facts) f-0 (MAIN::initial-fact) f-1 (MAIN::automobile (make Chrysler) (model LeBaron) (year 1997) (color white)) For a total of 2 facts in module MAIN.
Jess> (retract 1) TRUE Jess> (facts) f-0 (MAIN::initial-fact) For a total of 1 facts in module MAIN.
The fact (initial-fact) is asserted by the reset command. It is used internally by Jess to keep track of its own operations; you should generally not retract it.
A given slot in a deftemplate fact can normally hold only one value. If you want a slot that can hold multiple values, use the multislot keyword instead:
Jess> (deftemplate box (slot location) (multislot contents)) TRUE Jess> (bind ?id (assert (box (location kitchen) (contents spatula sponge frying-pan)))) <Fact-2>
Jess> (modify ?id (location dining-room)) <Fact-2> Jess> (facts) f-0 (MAIN::initial-fact) f-2 (MAIN::box (location dining-room) (contents spatula sponge frying-pan)) For a total of 2 facts in module MAIN.
Jess> (deftemplate used-auto extends automobile (slot mileage) (slot blue-book-value) (multislot owners)) TRUE
A used-auto fact would now have all the slots of an automobile, plus three more. As we'll see later, this inheritance relationship will let you act on all automobiles (used or not) when you so desire, or only on the used ones.
You can completely clear Jess of all facts and other data using the clear command.
5.1.1. The slot-specific declarationDeftemplate definitions can now include a "declare" section just as defrules can. There are several different properties that can be declared. One is "slot-specific". A template with this declaration will be matched in a special way: if a fact, created from such a template, which matches the left-hand-side of a rule is modified, the result depends on whether the modified slot is named in the pattern used to match the fact. As an example, consider the following:
(deftemplate D (declare (slot-specific TRUE)) (slot A) (slot B)) (defrule R ?d <- (D (A 1)) => (modify ?d (B 3)))
Without the "slot-specific" declaration, this rule would enter an endless loop, because it modifies a fact matched on the LHS in such a way that the modified fact will still match. With the declaration, it can simply fire once. This behavior is actually what many new users expect as the default, so the slot-specific declaration probably ought to be used most of the time.
5.2. Ordered facts
Most of the time, you will use unordered facts (or their cousins, definstance facts. They are nicely structured, and they're the most efficient kind of fact in Jess. In some cases, though, slot names are redundant, and force you to do more typing than you'd like. For example, if a fact represents a single number, it seems silly to use an unordered fact like this:
(number (value 6))
What you'd like would be a way to leave out that redundant "value" identifier. Ordered facts let you do exactly that.Ordered facts are simply Jess lists, where the first field (the head of the list) acts as a sort of category for the fact. Here are some examples of ordered facts:
(shopping-list eggs milk bread) (person "Bob Smith" Male 35) (father-of danielle ejfried)
Jess> (deftemplate father-of "A directed association between a father and a child." (declare (ordered TRUE)))
Note that an ordered fact is very similar to an unordered fact with only one multislot. The similarity is so strong, that in fact this is how ordered facts are implemented in Jess. If you assert an ordered fact, Jess automatically generates a template for it. This generated template will contain a single slot named "__data". Jess treats these facts specially - the name of the slot is normally hidden when the facts are displayed. This is really just a syntactic shorthand, though; ordered facts really are just unordered facts with a single multislot named "__data".
5.3. The deffacts constructTyping separate assert commands for each of many facts is rather tedious. To make life easier in this regard, Jess includes the deffacts construct. A deffacts construct is a simply a named list of facts. The facts in all defined deffacts are asserted into the working memory whenever a reset command is issued:
Jess> (deffacts my-facts "The documentation string" (foo bar) (box (location garage) (contents scissors paper rock)) (used-auto (year 1992) (make Saturn) (model SL1) (mileage 120000) (blue-book-value 3500) (owners ejfried))) TRUE Jess> (reset) TRUE Jess> (facts) f-0 (MAIN::initial-fact) f-1 (MAIN::foo bar) f-2 (MAIN::box (location garage) (contents scissors paper rock)) f-3 (MAIN::used-auto (make Saturn) (model SL1) (year 1992) (color white) (mileage 120000) (blue-book-value 3500) (owners ejfried)) For a total of 4 facts in module MAIN.