2. The Jess Language

I'm using an extremely informal notation to describe syntax. Basically strings in <angle-brackets> are some kind of data that must be supplied; things in [square brackets] are optional, things ending with + can appear one or more times, and things ending with * can appear zero or more times.

In general, input to Jess is free-format. Newlines are generally not significant and are treated as whitespace; exceptions will be noted.

2.1. Basics

2.1.1. Atoms

The atom or symbol is a core concept of the Jess language. Atoms are very much like identifiers in other languages. A Jess atom can contain letters, numbers, and the following punctuation: $*=+/<>_?#. . An atom may not begin with a number; it may begin with some punctuation marks (some have special meanings as operators when they appear at the start of an atom).

Jess atoms are case sensitive: foo, FOO and Foo are all different atoms.

The best atoms consist of letters, numbers, underscores, and dashes; dashes are traditional word separators. The following are all valid atoms:
  foo first-value contestant#1 _abc
There are three "magic" atoms that Jess interprets specially: nil, which is somewhat akin to Java's null value; and TRUE and FALSE, which are Jess' boolean values.

2.1.2. Numbers

Jess uses the Java functions java.lang.Integer.parseInt and java.lang.Double.parseDouble to parse integer and floating point numbers, respectively. See the documentation for those methods for a precise syntax description. The following are all valid numbers:
  3 4. 5.643 6.0E4 1D

2.1.3. Strings

Character strings in Jess are denoted using double quotes ("). Backslashes (\) can be used to escape embedded quote symbols. Note that Jess strings are unlike Java strings in several important ways. First, no "escape sequences" are recognized. You cannot embed a newline in a string using "\n", for example. On the other hand, real newlines are allowed inside double-quoted strings; they become part of the string. The following are all valid strings:
  "foo" "Hello, World" "\"Nonsense,\" he said firmly." "Hello,
The last string is equivalent to the Java string "Hello,\nThere".

2.1.4. Lists

Another fundamental unit of syntax in Jess is the list. A list always consists of an enclosing set of parentheses and zero or more atoms, numbers, strings, or other lists. The following are valid lists:
  (+ 3 2) (a b c) ("Hello, World") () (deftemplate foo (slot bar))
The first element of a list (the car of the list in LISP parlance) is often called the list's head in Jess.


Programmer's comments in Jess begin with a semicolon (;) and extend to the end of the line of text. Here is an example of a comment:
  ; This is a list
  (a b c)
Comments can appear anywhere in a Jess program.

2.2. Functions

As in LISP, all code in Jess (control structures, assignments, procedure calls) takes the form of a function call.

Function calls in Jess are simply lists. Function calls use a prefix notation; a list whose head is an atom that is the name of an existing function can be a function call. For example, an expression that uses the + function to add the numbers 2 and 3 would be written (+ 2 3). When evaluated, the value of this expression is the number 5 (not a list containing the single element 5!). In general, expressions are recognized as such and evaluated in context when appropriate. You can type expressions at the Jess> prompt. Jess evaluates the expression and prints the result:
Jess> (+ 2 3)
  Jess> (+ (+ 2 3) (* 3 3))

Note that you can nest function calls; the outer function is responsible for evaluating the inner function calls.

Jess comes with a large number of built-in functions that do everything from math, program control and string manipulations, to giving you access to Java APIs.

One of the most commonly used functions is printout. printout is used to send text to Jess's standard output, or to a file. A complete explanation will have to wait, but for now, all you need to know is contained in the following example:
Jess> (printout t "The answer is " 42 "!" crlf)
  The answer is 42!

Another useful function is batch. batch evaluates a file of Jess code. To run the Jess source file examples/hello.clp you can enter
Jess> (batch examples/hello.clp)
  Hello, world!

Each of these functions (along with all the others) is described more thoroughly in the Jess function guide.

2.3. Variables

Programming variables in Jess are atoms that begin with the question mark (?) character. The question mark is part of the variable's name. A normal variable can refer to a single atom, number, or string. A variable whose first character is instead a $ (for example, $?X) is a multivariable, which can refer to a special kind of list called a multifield. You assign to any variable using the bind function:
Jess> (bind ?x "The value")
  "The value"

Multifields are generally created using special multifield functions like create$ and can then be bound to multivariables:
Jess> (bind $?grocery-list (create$ eggs bread milk))
  (eggs bread milk)

Variables need not (and cannot) be declared before their first use (except for special variables called defglobals).

Note that to see the value of a variable at the Jess> prompt, you can simply type the variable's name.
Jess> (bind ?a 123)
  Jess> ?a

2.3.1. Global variables (or defglobals)

Any variables you create at the Jess> prompt, or at the "top level" of any Jess language program, are cleared whenever the reset command is issued. This makes them somewhat transient; they are fine for scratch variables but are not persistent global variables in the normal sense of the word. To create global variables that are not destroyed by reset, you can use the defglobal construct.
  (defglobal [?<global-name> = <value>]+)
Global variable names must begin and end with an asterisk. Valid global variable names look like
  ?*a*    ?*all-values*    ?*counter*
When a global variable is created, it is initialized to the given value. When the reset command is subsequently issued, the variable may be reset to this same value, depending on the current setting of the reset-globals property. There is a function named set-reset-globals that you can use to set this property. An example will help.
Jess> (defglobal ?*x* = 3)
  Jess> ?*x*
  Jess> (bind ?*x* 4)
  Jess> ?*x*
  Jess> (reset)
  Jess> ?*x*
  Jess> (bind ?*x* 4)
  Jess> (set-reset-globals nil)
  Jess> (reset)
  Jess> ?*x*

You can read about the set-reset-globals and the accompanying get-reset-globals function in the Jess function guide.

2.4. Deffunctions

You can define your own functions using the deffunction construct. A deffunction construct looks like this:
  (deffunction <function-name> [<doc-comment>] (<parameter>*)
The <function-name> must be an atom. Each <parameter> must be a variable name. The optional <doc-comment> is a double-quoted string that can describe the purpose of the function. There may be an arbitrary number of <expr> expressions. The optional <return-specifier> gives the return value of the function. It can either be an explicit use of the return function or it can be any value or expression. Control flow in deffunctions is achieved via control-flow functions like foreach, if, and while. The following is a deffunction that returns the larger of its two numeric arguments:
Jess> (deffunction max (?a ?b)
    (if (> ?a ?b) then
        (return ?a)
        (return ?b)))

Note that this could have also been written as:
Jess> (deffunction max (?a ?b)
    (if (> ?a ?b) then

This function can now be called anywhere a Jess function call can be used. For example
Jess> (printout t "The greater of 3 and 5 is " (max 3 5) "." crlf)
  The greater of 3 and 5 is 5.

Normally a deffunction takes a specific number of arguments. To write a deffunction that takes an arbitrary number of arguments, make the last formal parameter be a multifield variable. When the deffunction is called, this multifield will contain all the remaining arguments passed to the function. A deffunction can accept no more than one such wildcard argument, and it must be the last argument to the function.

2.5. Defadvice

Sometimes a Jess function won't behave exactly as you'd like. The defadvice construct lets you write some Jess code which will be executed before or after each time a given Jess function is called. defadvice lets you easily "wrap" extra code around any Jess function, such that it executes before (and thus can alter the argument list seen by the real function, or short-circuit it completely by returning a value of its own) or after the real function (and thus can see the return value of the real function and possibly alter it. ) defadvice provides a great way for Jess add-on authors to extend Jess without needing to change any internal code.

Here are some examples of what defadvice looks like.

This intercepts calls to 'plus' (+) and adds the extra argument '1', such that (+ 2 2) becomes (+ 2 2 1) -> 5. The variable '$?argv' is special. It always refers to the list of arguments the real Jess function will receive when it is called.
Jess> (defadvice before + (bind $?argv (create$ $?argv 1)))
  Jess> (+ 2 2)

This makes all additions equal to 1. By returning, the defadvice keeps the real function from ever being called.
Jess> (defadvice before + (return 1))
  Jess> (+ 2 2)

This subtracts one from the return value of the + function. ?retval is another magic variable - it's the value the real function returned. When we're done, we remove the advice with undefadvice.
Jess> (defadvice after + (return (- ?retval 1)))
  Jess> (+ 2 2)
  Jess> (undefadvice +)
  Jess> (+ 2 2)

2.6. Java reflection

Among the list of functions above are a set that let you create and manipulate Java objects directly from Jess. Using them, you can do virtually anything you can do from Java code, except for defining new classes. Here is an example in which I create a Java Hashtable and add a few String objects to it, then lookup one object and display it.
Jess> (bind ?ht (new java.util.Hashtable))
  Jess> (call ?ht put "key1" "element1")
  Jess> (call ?ht put "key2" "element2")
  Jess> (call ?ht get "key1")

As you can see, Jess converts freely between Java and Jess types when it can. Java objects that can't be represented as a Jess type are called external address values. The Hashtable in the example above is one of these.

Jess can also access member variables of Java objects using the set-member and get-member functions.
Jess> (bind ?pt (new java.awt.Point))
  Jess> (set-member ?pt x 37)
  Jess> (set-member ?pt y 42)
  Jess> (get-member ?pt x)

You can access static members by using the name of the class instead of an object as the first argument to these functions.
Jess> (get-member System out)

Note that we don't have to say "java.lang.System." The java.lang package is implicitly "imported" much as it is in Java code. Jess also has an import function that you can use explicitly.

Jess converts values from Java to Jess types according to the following table.

Java typeJess type
A null referenceThe atom 'nil'
A void return valueThe atom 'nil'
An arrayA Jess multifield
boolean or java.lang.BooleanThe atoms 'TRUE' and 'FALSE'
byte, short, int, or their wrappersRU.INTEGER
long or LongRU.LONG
double, float or their wrappersRU.FLOAT
char or java.lang.CharacterRU.ATOM

Jess converts values from Jess to Java types with some flexibility, according to this table. Generally when converting in this direction, Jess has some idea of a target type; i.e., Jess has a java.lang.Class object and a jess.Value object, and wants to turn the Value's contents into something assignable to the type named by the Class. Hence the atom 'TRUE' could be passed to a function expecting a boolean argument, or to one expecting a String argument, and the call would succeed in both cases.

Jess typePossible Java types
RU.EXTERNAL_ADDRESSThe wrapped object
The atom 'nil'A null reference
The atoms 'TRUE' or 'FALSE'java.lang.Boolean or boolean
RU.ATOM, RU.STRINGString, char, java.lang.Character
RU.FLOATfloat, double, and their wrappers
RU.INTEGERlong, short, int, byte, char, and their wrappers
RU.LONGlong, short, int, byte, char, and their wrappers
RU.LISTA Java array

Sometimes you might have trouble calling overloaded methods - for example, passing the String "TRUE" to a Java method that is overloaded to take either a boolean or a String. In this case, you can always resort to using an explicit wrapper class - in this case, passing a java.lang.Boolean object should fix the problem.

To learn more about the syntax of call, new, set-member, get-member, and other Java integration functions, see the Jess function guide.

2.7. The knowledge base

A rule-based system maintains a collection of knowledge nuggets called facts. This collection is known as the knowledge base. It is somewhat akin to a relational database, especially in that the facts must have a specific structure. In Jess, there are three kinds of facts: ordered facts, unordered facts, and definstance facts.

2.7.1. Ordered facts

Ordered facts are simply 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)
You can add ordered facts to the knowledge base using the assert function. You can see a list of all the facts in the knowledge base using the facts command. You can completely clear Jess of all facts and other data using the clear command.
Jess> (reset)
  Jess> (assert (father-of danielle ejfried))
  Jess> (facts)
  f-0   (MAIN::initial-fact)
  f-1   (MAIN::father-of danielle ejfried)
  For a total of 2 facts.

As you can see, each fact is assigned an integer index (the fact-id) when it is asserted. You can remove an individual fact from the knowledge base using the retract function.
Jess> (retract (fact-id 1))
  Jess> (facts)
  f-0   (MAIN::initial-fact)
  For a total of 1 facts.

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.

2.7.2. Unordered facts

Ordered facts are useful, but they are unstructured. Sometimes (most of the time) you need a bit more organization. In 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))
before you can create unordered facts, you have to define the slots they have using the deftemplate construct:
  (deftemplate <deftemplate-name> [extends <classname>] [<doc-comment>]
     [(slot <slot-name> [(default | default-dynamic <value>)]
                           [(type <typespec>))]*)
The <deftemplate-name> is the head of the facts that will be created using this template. There may be an arbitrary number of slots. Each <slot-name> must be an atom. The default slot qualifier states that the default value of a slot in a new fact is given by <value>; the default is the atom nil. The 'default-dynamic' version will evaluate the given value each time a new fact using this template is asserted. The 'type' slot qualifier is accepted but not currently enforced by Jess; it specifies what data type the slot is allowed to hold. Acceptable values are ANY, INTEGER, FLOAT, NUMBER, ATOM, STRING, LEXEME, and OBJECT.

As an example, defining the following template:
Jess> (deftemplate automobile
    "A specific car."
    (slot make)
    (slot model)
    (slot year (type INTEGER))
    (slot color (default white)))
would allow you to define facts like this:
Jess> (assert (automobile (make Chrysler) (model LeBaron)
          (year 1997)))
  Jess> (facts)
  f-0   (MAIN::automobile (make Chrysler) (model LeBaron)
                    (year 1997) (color white))
  For a total of 1 facts.

Note that the car is white by default. If you don't supply a default value for a slot, and then don't supply a value when a fact is asserted, the special value nil is used. Also note that any number of additional automobiles could also be simultaneously asserted onto the fact list using this template.

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))
  Jess>   (bind ?id (assert (box (location kitchen)
                    (contents spatula sponge frying-pan))))

(We're saving the fact-id returned by (assert) in the variable ?id, for use below.) A multislot has the default value () (the empty list) if no other default is specified.

You can change the values in the slots of an unordered fact using the modify command. Building on the immediately preceding example, we can move the box into the dining room:
Jess> (modify ?id (location dining-room))
  Jess> (facts)
  f-0   (MAIN::automobile (make Chrysler) (model LeBaron)
                    (year 1997) (color white))
  f-1   (MAIN::box (location dining-room)
             (contents spatula sponge frying-pan))
  For a total of 2 facts.

The optional extends clause of the deftemplate construct lets you define one template in terms of another. For example, you could define a used-auto as a kind of automobile with more data:
Jess> (deftemplate used-auto extends automobile
    (slot mileage)
    (slot blue-book-value)
    (multislot owners))

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.

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".

2.7.3. The deffacts construct

Typing 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 knowledge base 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)))
  Jess> (reset)
  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.

Note that we can specify the slots of an unordered fact in any order (hence the name.) Jess rearranges our inputs into a canonical order so that they're always the same.

2.7.4. Definstance facts

You may have noticed that unordered facts look a bit like Java objects, or specifically, like Java Beans. The similarity is that both have a list of slots (for Java Beans, they're called properties) which contains values that might change over time. Jess has a mechanism for automatically generating templates that represent specific types of Java Beans. Jess can then use these templates to store a representation of a Java Bean's properties on the knowledge base. The knowledge base representation of the Bean can be static (changing infrequently, like a snapshot of the properties at one point in time) or dynamic (changing automatically whenever the Bean's properties change.) The Jess commands that make this possible are defclass and definstance. defclass tells Jess to generate a special template to represent a category of Beans, while definstance puts a representation of one specific Bean onto the fact base.

An example will probably help at this point. Let's say you have the following Java Bean class

  import java.io.Serializable;
  public class ExampleBean implements Serializable
    private String m_name = "Bob";
    public String getName() { return m_name; }
    public void setName(String s) { m_name = s; }

This Bean has one property called "name". Before we can insert any of these Beans onto the knowledge base, we need a template to represent them: we must use defclass to tell Jess to generate it:
Jess> (defclass simple ExampleBean)
  Jess> (ppdeftemplate simple)  
  "(deftemplate MAIN::simple extends MAIN::__fact \"$JAVA-OBJECT$ ExampleBean\"
   (slot class (default <External-Address:jess.SerializablePD>))
   (slot name (default <External-Address:jess.SerializablePD>))
   (slot OBJECT (type 2048)))"

This is a strange looking template, but it does have a slot called "name", as we'd expect, that arises from the "name" property of our Bean. The slot "class" comes from the method getClass() that every object inherits from java.lang.Object, while the slot OBJECT is added by Jess; its value is always a reference to the Bean itself. See how the first argument to defclass is used as the template name.
Note that if you want your Java Beans to work with Jess's bload and bsave commands, the individual classes need to implement the java.io.Serializable tag interface.
Now let's say we want an actual ExampleBean in our knowledge base. Here we'll create one from Jess code, but it could come from anywhere. We will use the definstance function to add the object to the knowledge base.
Jess> (bind ?sb (new ExampleBean))
  Jess> (definstance simple ?sb static)
  Jess> (facts)
  f-0   (MAIN::simple (class <External-Address:java.lang.Class>)
                (name "Bob")
                (OBJECT <External-Address:ExampleBean>))
  For a total of 1 facts.

As soon as we issue the definstance command, a fact representing the Bean appears in the knowledge base.

Now watch what happens if we change the "name" property of our Bean.
Jess> (call ?sb setName "Fred")
  Jess> (facts)
  f-0   (MAIN::simple (class <External-Address:java.lang.Class>)
                (name "Bob")
                (OBJECT <External-Address:ExampleBean>))
  For a total of 1 facts.

Hmmm. The knowledge base still thinks our Bean's name is "Bob", even though we changed it to "Fred". What happens if we issue a reset command?
Jess> (reset)
  Jess> (facts)
  f-0   (MAIN::initial-fact)
  f-1   (MAIN::simple (class <External-Address:java.lang.Class>)
                (name "Fred")
                (OBJECT <External-Address:ExampleBean>))
  For a total of 2 facts.

reset updates the definstance facts in the knowledge base to match their Java Beans. This behaviour is what you get when (as we did here) you specify static in the definstance command. Static definstances are refreshed only when a reset is issued.

If you want to have your definstance facts stay continuously up to date, Jess needs to be notified whenever a Bean property changes. For this to happen, the Bean has to support the use of java.beans.PropertyChangeListeners. For Beans that fulfill this requirement, you can specify dynamic in the definstance command, and the knowledge base will be updated every time a property of the Bean changes. Jess comes with some example Beans that can be used in this way; see, for example, the Jess61p7/jess/examples/simple directory.

defclasses, like deftemplates, can extend one another. In fact, deftemplates can extend defclasses, and defclasses can extend deftemplates. Of course, for a defclass to extend a deftemplate, the corresponding Bean class must have property names that match the template's slot names. Note, also, that just because two Java classes have an inheritance relationship doesn't mean that if both are defclassed the two defclasses will. You must explicitly declare all such relationships using extends. See the full documenation for defclass for details.

One final note about Java Beans used with Jess: Beans are often operating in a multithreaded environment, and so it's important to protect their data with synchronized blocks or synchronized methods. However, sending PropertyChangeEvents while holding a lock on the Bean itself can be dangerous, as the Java Beans Specification points out:
"In order to reduce the risk of deadlocks, we strongly recommend that event sources should avoid holding their own internal locks when they call event listener methods. Specifically, as in the example code in Section 6.5.1, we recommend they should avoid using a synchronized method to fire an event and should instead merely use a synchronized block to locate the target listeners and then call the event listeners from unsynchronized code." -- JavaBean Specification, v 1.0.1, p.31.
Failing to heed this advice can indeed cause deadlocks in Jess.

2.8. Defrules

Now that we've learned how to develop a knowledge base, we can answer the obvious question: what is it good for? The answer is that queries can search it to find relationships between facts, and rules can take actions based on the contents of one or more facts.

A Jess rule is something like an if... then statement in a procedural language, but it is not used in a procedural way. While if... then statements are executed at a specific time and in a specific order, according to how the programmer writes them, Jess rules are executed whenever their if parts (their left-hand-sides or LHSs) are satisfied, given only that the rule engine is running. This makes Jess rules less deterministic than a typical procedural program. See the chapter on the Rete algorithm for an explanation of why this architecture can be many orders of magnitude faster than an equivalent set of traditional if... then statements.

Rules are defined in Jess using the defrule construct. A very simple rule looks like this:
Jess> (defrule do-change-baby
    "If baby is wet, change baby's diaper."
This rule has two parts, separated by the "=>" symbol (which you can read as "then".) The first part consists of the LHS pattern (baby-is-wet). The second part consists of the RHS action (change-baby). Although it's hard to tell due to the LISP-like syntax, the LHS of a rule consists of patterns which are used to match facts in the knowledge base, while the RHS contains function calls.
The LHS of a rule (the "if" part) consists of patterns that match facts, NOT function calls. The actions of a rule (the "then" clause) are made up of function calls. The following rule does NOT work:
Jess> (defrule wrong-rule
      (eq 1 1)
      (printout t "Just as I thought,  1 == 1!" crlf))
This rule will NOT fire just because the function call (eq 1 1) would evaluate to true. Instead, Jess will try to find a fact on the knowledge base that looks like (eq 1 1). Unless you have previously asserted such a fact, this rule will NOT be activated and will not fire. If you want to fire a rule based on the evaluation of a function, you can use the test CE.
Our example rule, then, will be activated when the fact (baby-is-wet) appears in the knowledge base. When the rule executes, or fires, the function (change-baby) is called (presumably this function is defined elsewhere in our imaginary program.) Let's turn this rule into a complete program. The function watch all tells Jess to print some useful diagnostics as we enter our program.
Jess> (watch all)
  Jess>  (reset)
  ==> f-0 (MAIN::initial-fact)
  Jess> (deffunction change-baby () (printout t "Baby is now dry" crlf))
  Jess> (defrule do-change-baby
  MAIN::do-change-baby: +1+1+1+t
  Jess>  (assert (baby-is-wet))
   ==> f-1 (MAIN::baby-is-wet)
  ==> Activation: MAIN::do-change-baby :  f-1

Some of these diagnostics are interesting. We see first of all how issuing the reset command asserts the fact (initial-fact). You should always issue a reset command when working with rules. When the rule itself is entered, we see the line "+1+1+1+t". This tells you something about how the rule is interpreted by Jess internally (see The Rete Algorithm for more information.) When the fact (baby-is-wet) is asserted, we see the diagnostic "Activation: MAIN::do-change-baby : f-1". This means that Jess has noticed that the rule do-change-baby has all of its LHS conditions met by the given list of facts ("f-1").

After all this, our rule didn't fire; why not? Jess rules only fire while the rule engine is running (although they can be activated while the engine is not running.) To start the engine running, we issue the run command.
Jess> (run)
  FIRE 1 MAIN::do-change-baby f-1
  Baby is now dry
  <== Focus MAIN

As soon as we enter the run command, the activated rule fires. Since we have watch all, Jess prints the diagnostic FIRE 1 do-change-baby f-1 to notify us of this. We then see the output of the rule's RHS actions. The final number "1" is the number of rules that fired (it is the return value of the run command.) The run function returns when there are no more activated rules to fire.

What would happen if we entered (run) again? Nothing. A rule will be activated only once for a given set of facts; once it has fired, that rule will not fire again for the same list of facts. We won't change the baby again until the (baby-is-wet) fact is retracted (perhaps by (reset) and asserted again. In fact, this rule should itself retract the (baby-is-wet) fact itself; to learn how, see the section on pattern bindings, below.

Rules are uniquely identified by their name. If a rule named my-rule exists, and you define another rule named my-rule, the first version is deleted and will not fire again, even if it was activated at the time the new version was defined.

2.8.1. Basic Patterns

If all the patterns of a rule had to be given literally as above, Jess would not be very powerful. However, patterns can also include wildcards and various kinds of predicates (comparisons and boolean functions). You can specify a variable name instead of a value for a field in any of a rule's patterns (but not the pattern's head). A variable matches any value in that position within a rule. For example, the rule:
Jess> (defrule example-2
    (a ?x ?y)
    (printout t "Saw 'a " ?x " " ?y "'" crlf))
will be activated each time any fact with head a having two fields is asserted: (a b c), (a 1 2), (a a a), and so forth. As in the example, the variables thus matched in the patterns (or LHS) of a rule are available in the actions (RHS) of the same rule.

Each such variable field in a pattern can also include any number of tests to qualify what it will match. Tests follow the variable name and are separated from it and from each other by ampersands (&) or pipes (|). (The variable name itself is actually optional.) Tests can be:

Ampersands (&) represent logical "and", while pipes (|) represent logical "or." & has a higher precedence than |, so that the following
    (foo ?X&:(oddp ?X)&:(< ?X 100)|0)
matches a foo fact with a single field containing either an odd number less than 100, or 0.

Here's an example of a rule that uses several kinds of tests:
Jess> (defrule example-3
    (not-b-and-c ?n1&~b ?n2&~c)
    (different ?d1 ?d2&~?d1)
    (same ?s ?s)
    (more-than-one-hundred ?m&:(> ?m 100))
    (red-or-blue red|blue)
    (printout t "Found what I wanted!" crlf))
The first pattern will match a fact with head not-b-and-c with exactly two fields such that the first is not b and the second is not c. The second pattern will match any fact with head different and two fields such that the two fields have different values. The third pattern will match a fact with head same and two fields with identical values. The fourth pattern matches a fact with head more-than-one-hundred and a single field with a numeric value greater than 100. The last pattern matches a fact with head red-or-blue followed by either the atom red or the atom blue.

A few more details about patterns: you can match a field without binding it to a variable by omitting the variable name and using just a question mark (?) as a placeholder. You can match any number of fields in a multislot or unordered fact using a multivariable (one starting with $?):
Jess> (defrule example-4
    (grocery-list $?list)
    (printout t "I need to buy " $?list crlf))
  Jess> (assert (grocery-list eggs milk bacon))
  Jess> (run)
  I need to buy (eggs milk bacon)

If you match to a defglobal with a pattern like (foo ?*x*), the match will only consider the value of the defglobal when the fact is asserted. Subsequent changes to the defglobal's value will not invalidate the match - i.e., the match does not reflect the current value of the defglobal, but only the value at the time the matching fact was asserted.

2.8.2. Pattern bindings

Sometimes you need a handle to an actual fact that helped to activate a rule. For example, when the rule fires, you may need to retract or modify the fact. To do this, you use a pattern-binding variable:
Jess> (defrule example-5
    ?fact <- (a "retract me")
    (retract ?fact))
The variable (?fact, in this case) is bound to the particular fact that activated the rule.

Note that ?fact is a jess.Value object of type RU.FACT, not an integer. It is basically a reference to a jess.Fact object. You can convert an ordinary number into a FACT using the fact-id function. You can convert a FACT into an integer when necessary by using reflection to call the Fact.getFactId() function. The jess.Value.factValue() method can be called on a FACT Value to obtain the actual jess.Fact object from Java code. In Jess code, a fact-id essentially is a jess.Fact, and you can call jess.Fact methods on a fact-id directly:

Jess> (defrule example-5-1
  ?fact <- (initial-fact)
  (printout t (call ?fact getName) crlf))
  Jess> (reset)
  Jess> (run)

See the section on the jess.FactIDValue class for more information.

Note that once a fact is asserted, Jess will always use the same jess.Fact object to represent it, even if the original fact is modified. Therefore, you can store references to fact objects in the slots of other facts as a way of representing structured data.

2.8.3. Salience and conflict resolution

Each rule has a property called salience that is a kind of rule priority. Activated rules of the highest salience will fire first, followed by rules of lower salience. To force certain rules to always fire first or last, rules can include a salience declaration:
Jess> (defrule example-6
    (declare (salience -100))
    (command exit-when-idle)
    (printout t "exiting..." crlf))
Declaring a low salience value for a rule makes it fire after all other rules of higher salience. A high value makes a rule fire before all rules of lower salience. The default salience value is zero. Salience values can be integers, global variables, or function calls. See the set-salience-evaluation command for details about when such function calls will be evaluated.

The order in which multiple rules of the same salience are fired is determined by the active conflict resolution strategy. Jess comes with two strategies: "depth" (the default) and "breadth." In the "depth" strategy, the most recently activated rules will fire before others of the same salience. In the "breadth" strategy, rules fire in the order in which they are activated. In many situations, the difference does not matter, but for some problems the conflict resolution strategy is important. You can write your own strategies in Java; see the chapter on extending Jess with Java for details. You can set the current strategy with the set-strategy command.

Note that the use of salience is generally discouraged, for two reasons: first it is considered bad style in rule-based programming to try to force rules to fire in a particular order. Secondly, use of salience will have a negative impact on performance, at least with the built-in conflict resolution strategies.

You can see the list of activated, but not yet fired, rules with the agenda command.

2.8.4. The 'and' conditional element.

Any number of patterns can be enclosed in a list with and as the head. The resulting pattern is matched if and only if all of the enclosed patterns are matched. By themselves, and groups aren't very interesting, but combined with or and not conditional elements, they can be used to construct complex logical conditions.

The entire left hand side of every rule and query is implicitly enclosed in an and conditional element.

2.8.5. The 'or' conditional element.

Any number of patterns can be enclosed in a list with or as the head. The resulting pattern is matched if one or more of the patterns inside the or are matched. If more than one of the subpatterns are matched, the or is matched more than once:
Jess> (defrule or-example-1
     (or (a) (b) (c))
  Jess> (assert (a) (b) (c))
  Jess> (printout t (run) crlf)

An and group can be used inside of an or group, and vice versa. In the latter case, Jess will rearrange the patterns so that there is a single or at the top level. For example, the rule
      (defrule or-example-2a
          (and (or (a)
will be automatically rearranged to
      (defrule or-example-2b
          (or (and (a) (c))
              (and (b) (c)))
DeMorgan's second rule of logical equivalence, namely
    (not (or (x) (y)))  => (and (not (x)) (not (y)))
will be used when necessary to hoist an or up to the top level.

Note that if the right hand side of a rule uses a variable defined by matching on the left hand side of that rule, and the variable is defined by one or more branches of an or pattern but not all branches, then a runtime error may occur. Subrule generation and the 'or' conditional element.
A rule containing an 'or' conditional element with n branches is precisely equivalent to n rules, each of which has one branch as its left hand side. In fact, this is how the or conditional element is implemented: Jess imternally generates one new rule for each branch. Each of these generated rules is a subrule. For a rule named rule-name, the first subrule is named rule-name, the second is rule-name&1, the third is rule-name&2, etc. Each of these subrules is added to the Rete network individually. If you execute the (rules) command, you will see each of them listed separately. If you use the
ppdefrule function to see a pretty-print representation of a subrule, you will see only the representation of that rule. Note that since '&' is a token delimiter in the Jess grammar, you can only refer to a subrule with an ampersand in the name by placing the whole name in quotes; i.e., (ppdefrule "rule-name&6").

Jess knows that the subrules created from a given rule are related. If a rule is removed (either using undefrule or implicitly by defining a new rule with the same name as an existing one) every subrule associated with that rule is undefined.

Regarding subrules and efficiency: remember that similar patterns are shared between rules in the Rete network. Therefore, splitting a rule into subrules does not mean that the amount of pattern-matching work is increased; much of the splitting may indeed be undone when the rules are compiled into the network.

On the other hand, keep the implementation in mind when you define your rules. If an or conditional element is the first pattern on a rule, all the subsequent pattern-matching on that rule's left-hand side won't be shared between the subrules, since sharing only occurs as far as two rules are similar reading from the top down. Placing or conditional elements near the end of a rule will lead to more sharing between the subrules.
Note: although subrules will probably always be part of the implementation of the or conditional element in Jess, it is very likely that they will no longer be user-visible at some time in the future.

2.8.6. The 'not' conditional element.

Any single pattern can be enclosed in a list with not as the head. In this case, the pattern is considered to match if a fact (or set of facts) which matches the pattern is not found. For example:
Jess> (defrule example-7
     (person ?x)
     (not (married ?x))
     (printout t ?x " is not married!" crlf))
Note that a not pattern cannot define any variables that are used in subsequent patterns (since a not pattern does not match any facts, it cannot be used to define the values of any variables!) You can introduce variables in a not pattern, so long as they are used only within that pattern; i.e,
Jess> (defrule no-odd-numbers
     (not (number ?n&:(oddp ?n)))
     (printout t "There are no odd numbers." crlf))
Similarly, a not pattern can't have a pattern binding.

A not CE is evaluated only when either a fact matching it exists, or when the pattern immediately before the not on the rule's LHS is evaluated. If a not CE is the first pattern on a rule's LHS, or is the the first the pattern in an and group, or is the only pattern on a given branch of an or group, the pattern (initial-fact) is inserted to become this important preceding pattern. Therefore, the fact (initial-fact) created by the reset command is necessary to the proper functioning of some not patterns. For this reason, it is especially important to issue a reset command before attempting to run the rule engine when working with not patterns.

Multiple not CEs can be nested to produce some interesting effects (see the discussion of the exists CE).

The not CE can be used in arbitrary combination with the and and or CEs. You can define complex logical structures this way. For example, suppose you want a rule to fire once if for every fact (a ?x), there is a fact (b ?x). You could express that as
Jess> (defrule forall-example
    (not (and (a ?x) (not (b ?x))))
i.e., "It is not true that for some ?x, there is an (a ?x) and no (b ?x)". You might recognize this as the CLIPS forall conditional element; a future version of Jess will include the forall shorthand.

2.8.7. The 'test' conditional element.

A pattern with test as the head is special; the body consists not of a pattern to match against the knowledge base but of one or more boolean functions, which are evaluated in order. The results determine whether the pattern matches. A test pattern fails if and only if one of the functions evaluates to the atom FALSE; if they all evaluate to TRUE or any other value, the pattern with "match." For example:
Jess> (deftemplate person (slot age))
  Jess> (defrule example-8
     (person (age ?x))
     (test (> ?x 30))
     (printout t ?x " is over 30!" crlf))
Short-circuit evaluation is used; i.e., if a function call evaluates to FALSE, no further functions are evaluated and the test CE fails immediately. Note that a test pattern, like a not, cannot contain any variables that are not bound before that pattern. test and not may be combined:
  (not (test (eq ?X 3)))
is equivalent to:
  (test (neq ?X 3))

A test CE is evaluated every time the preceding pattern on the rule's LHS is evaluated. Therefore the following two rules are precisely equivalent in behaviour:
Jess> (defrule rule_1
    (foo ?X)
    (test (> ?X 3))

  Jess> (defrule rule_2
    (foo ?X&:(> ?X 3))

For rules in which a test CE is the first pattern on the LHS or the first pattern in a branch of an or CE, the pattern (initial-fact) is inserted to become the "preceding pattern" for the test. The fact (initial-fact) is therefore also important for the proper functioning of the test conditional element; the caution about reset in the preceding section applies equally to test. Time-varying method returns

One useful property of the test CE is that it's the only valid place to put tests whose results might change without the contents of any slot changing. For example, imagine that you've got two Java class, A and B, and that A has a method contains which takes a B as an argument and returns boolean. Further, imagine that for any given B object, the return value of contains will change over time. Finally, imagine that you've defclasses both these classes and are writing rules to work with them. Under these circumstances, a set of patterns like this:
    (A (OBJECT ?a))
    (B (OBJECT ?b&:(?a contains ?b)))
is incorrect. If the return value of contains changes, the match will be invalidated and Jess's internal data structures may be corrupted. In particular, this kind of construct tends to cause memory leaks.

The correct way to express this same set of patterns is to use the test conditional element, like this:
    (A (OBJECT ?a))
    (B (OBJECT ?b))
    (test (?a contains ?b))
The function contains is now guaranteed to be called at most once for each combination of target and argument, and so any variation in return value will have no impact.

2.8.8. The 'logical' conditional element.

The logical conditional element lets you specify logical dependencies among facts. All the facts asserted on the RHS of a rule become dependent on the matches to the logicalpatterns on that rule's LHS. If any of the matches later become invalid, the dependent facts are retracted automatically. In this simple example, a single fact is made to depend on another single fact:
Jess> (defrule rule-1
    (logical (faucet-open))
    (assert (water-flowing)))
  Jess> (assert (faucet-open))
  Jess> (run)
  Jess> (facts)
  f-0   (MAIN::faucet-open)
  f-1   (MAIN::water-flowing)
  For a total of 2 facts.
  Jess> (watch facts)
  Jess> (retract (fact-id 0))
  <== f-0 (MAIN::faucet-open)
  <== f-1 (MAIN::water-flowing)

The (water-flowing) fact is logically dependent on the (faucet-open) fact, so when the latter is retracted, the former is removed, too.

A fact may receive logical support from multiple sources -- i.e., it may be asserted multiple times with a different set of logical supports each time. Such a fact isn't automatically retracted unless each of its logical supports is removed.

If a fact is asserted without explicit logical support, it is said to be unconditionally supported. If an unconditionally supported fact also receives explicit logical support, removing that support will not cause the fact to be retracted.

If one or more logical CEs appear in a rule, they must be the first patterns in that rule; i.e., a logical CE cannot be preceded in a rule by any other kind of CE.

Definstance facts are no different than other facts with regard to the logical CE. Definstance facts can provide logical support and can receive logical support. In the current implementation, definstance facts can only provide logical support as a whole. In a future version of Jess, it will be possible for a definstance fact to provide logical support based on any combination of individual slot values.

The logical CE can be used together with all the other CEs, including not and exists. A fact can thus be logically dependent on the non-existence of another fact, or on the existence of some category of facts in general.

2.8.9. The 'unique' conditional element.

The unique CE has been removed. The parser will accept but ignore it.

2.8.10. The 'exists' conditional element.

A pattern can be enclosed in a list with exists as the head. An exists CE is true if there exist any facts that match the pattern, and false otherwise. exists is useful when you want a rule to fire only once, although there may be many facts that could potentially activate it.
Jess> (defrule exists-demo
    (exists (honest ?))
    (printout t "There is at least one honest man!" crlf))
If there are any honest men in the world, the rule will fire once and only once.

exists may not be combined in the same pattern with a test CE.

Note that exists is precisely equivalent to (and in fact, is implemented as) two nested not CEs; i.e., (exists (A)) is the same as (not (not (A))).

2.8.11. Node index hash value.

The node index hash value is a tunable performance-related parameter that can be set globally or on a per-rule basis. A small value will save memory, possibly at the expense of performance; a larger value will use more memory but lead to faster rule LHS execution.

In general, you might want to declare a large value for a rule that was likely to generate many partial matches (prime numbers are the best choices:)
Jess> (defrule nihv-demo
      (declare (node-index-hash 169))
      (item ?a)
      (item ?b)
      (item ?c)
      (item ?d)
See the discussion of the set-node-index-hash function for a full discussion of this value and what it means.

2.8.12. Forward and backward chaining

The rules we've seen so far have been forward-chaining rules, which basically means that the rules are treated as if... then statements, with the engine passively executing the RHSs of activated rules. Some rule-based systems, notable Prolog and its derivatives, support backward chaining. In a backwards chaining system, rules are still if... then statements, but the engine seeks steps to activate rules whose preconditions are not met. This behaviour is often called "goal seeking". Jess supports both forward and backward chaining. Note that the explanation of backward chaining in Jess is necessarily simplified here since full explanation requires a good understanding of the underlying algorithms used by Jess.

To use backward chaining in Jess, you must first declare that certain fact templates will be backward chaining reactive using the do-backward-chaining function:
Jess> (do-backward-chaining factorial)
If the template is unordered -- i.e., if it is explicitly defined with a (deftemplate) construct -- then it must be defined before calling do-backward-chaining. Then you can define rules which match such patterns. Note that do-backward-chaining must be called before defining any rules which use the template.
Jess> (defrule print-factorial-10
    (factorial 10 ?r1)
    (printout t "The factorial of 10 is " ?r1 crlf))
When the rule compiler sees that a pattern matches a backward chaining reactive template, it rewrites the rule and inserts some special code into the internal representation of the rule's LHS. This code asserts a fact onto the fact-list that looks like
  (need-factorial 10 nil)
if, when the rule engine is reset, there are no matches for this pattern. The head of the fact is constructed by taking the head of the reactive pattern and adding the prefix "need-".

Now, you can write rules which match these need-(x) facts.
Jess> (defrule do-factorial
    (need-factorial ?x ?)
    (bind ?r 1)
    (bind ?n ?x)
    (while (> ?n 1)
      (bind ?r (* ?r ?n))
      (bind ?n (- ?n 1)))
    (assert (factorial ?x ?r)))
The rule compiler rewrites rules like this too: it adds a negated match for the factorial pattern itself to the rule's LHS.

The end result is that you can write rules which match on (factorial), and if they are close to firing except they need a (factorial) fact to do so, any (need-factorial) rules may be activated. If these rules fire, then the needed facts appear, and the (factorial)-matching rules fire. This, then, is backwards chaining! Jess will chain backwards through any number of reactive patterns. For example:
Jess> (do-backward-chaining foo)
  Jess> (do-backward-chaining bar)
  Jess> (defrule rule-1
    (foo ?A ?B)
    (printout t foo crlf))
  Jess> (defrule create-foo
    (need-foo $?)
    (bar ?X ?Y)
    (assert (foo A B)))
  Jess> (defrule create-bar
    (need-bar $?)
    (assert (bar C D)))
  Jess> (reset)
  Jess> (run)

In this example, none of the rules can be activated at first. Jess sees that rule-1 could be activated if there were an appropriate foo fact, so it generates the request (need-foo nil nil). This matches part of the LHS of rule create-foo cannot fire for want of a bar fact. Jess therefore creates a (need-bar nil nil) request. This matches the LHS of the rule create-bar,which fires and asserts (bar C D). This activates create-foo, which fires, asserts (foo A B), thereby activating rule-1, which then fires.

There is a special conditional element, (explicit), which you can wrap around a pattern to inhibit backwards chaining on an otherwise reactive pattern.

2.9. Defqueries

The defquery construct lets you create a special kind of rule with no right-hand-side. While rules act spontaneously, queries are used to search the knowledge base under direct program control. A rule is activated once for each matching set of facts, while a query gives you a java.util.Iterator of all the matches. An example should make this clear. Suppose we have defined this query:
Jess> (defquery search
    "Finds foo facts with a specified first field"
    (declare (variables ?X))
    (foo ?X ?Y))
Then if the knowledge base contains these facts:
Jess> (deffacts data
     (foo blue red)
     (bar blue green)
     (foo blue pink)
     (foo red blue)
     (foo blue blue)
     (foo orange yellow)
     (bar blue purple))
Then the following Jess code Will print the output shown:
Jess> (reset)
     Jess> (bind ?it (run-query search blue))

     Jess> (while (?it hasNext)
            (bind ?token (call ?it next))
            (bind ?fact (call ?token fact 1))
            (bind ?slot (fact-slot-value ?fact __data))
            (bind ?datum (nth$ 2 ?slot))
            (printout t ?datum crlf))


because these three values follow blue in a foo fact.

Let's break this code down to see what it's doing. As previously stated, (run-query) returns the query results as a java.util.Iterator. The Iterator interface has a method next() that you call to retrieve each individual result; it also has a hasNext() method which returns true as long as there are more results to return. That explains the (while (?it hasNext) ... (call ?it next)) structure.

Each individual result is a jess.Token object. A token is basically just a collection of jess.Fact objects; here it is a collection that matches this query. We call the fact() method of jess.Token to retrieve the individual facts within the Token. Note that each match begins with an extra fact - a __query-trigger fact that triggers the matching process, asserted by the run-query command; hence the argument to the call to Token.fact() above is 1, not 0.

Once we have the right fact, we're interested in the second item in the data part of the fact (the first item in the fact is the head and it's stored differently.) As stated above, the slot data for ordered facts is stored in a single multifield slot named __data. We retrieve the contents of that slot using the fact-slot-value function, then use the nth$ function to retrieve the second slot (nth$ uses a one-based index.)

The following Java code is similar to the Jess snippets above. It defines the same query and deffacts, runs the query and then collects the red, pink and blue values in a Vector as Strings.
  import jess.*;
  import java.util.*;

  public class ExQuery
    public static void main(String [] argv) throws JessException
      // Create engine, define query and data
      Rete r = new Rete();
      r.executeCommand("(defquery search (declare (variables ?X)) (foo ?X ?Y))");
      r.executeCommand("(deffacts data" +
                         "(foo blue red)" +
                         "(bar blue green)" +
                         "(foo blue pink)" +
                         "(foo red blue)" +
                         "(foo blue blue)" +
                         "(foo orange yellow)" +
                         "(bar blue purple))");

      // Assert all the facts
      // Run the query, store the result
      r.store("RESULT", r.runQuery("search",
                        new ValueVector().add(new Value("blue", RU.ATOM))));
      r.executeCommand("(store RESULT (run-query search blue))");

      // Fetch the result (an Iterator).
      Iterator e = (Iterator) r.fetch("RESULT").externalAddressValue(null);
      ArrayList v = new ArrayList();

      // Pick each element of the Iterator apart and store the
      // interesting part in the ArrayList v.
      while (e.hasNext())
        Token t = (Token) e.next();

        // We want the second fact in the token - the first is the query trigger
        Fact f = t.fact(1);

        // The first and only slot of this fact is the __data multislot.
        ValueVector multislot = f.get(0).listValue(null);

        // The second element of this slot is the datum we're interested in.
      for (Iterator answers = v.iterator(); answers.hasNext();)
  C:\> java ExQuery

Defqueries can use virtually all of the same features that rule LHSs can, except for salience. You can use the node-index-hash declaration, just as for rules.

2.9.1. The variable declaration

You might have already realized that two different kinds of variables can appear in a query: those that are "internal" to the query, like ?Y in the query above, and those that are "external", or to be specified in the run-query command when the query is executed. Jess assumes all variables in a query are internal by default; you must declare any external variables explicitly using the syntax
  (declare (variables ?X ?Y ...))
which is quite similar to the syntax of a rule salience declaration.

2.9.2. The max-background-rules declaration

It can be convenient to use queries as triggers for backward chaining. For this to be useful, Rete.run() must be called while the query is being evaluated, to allow the backward chaining to occur. Facts generated by rules fired during this run may appear as part of the query results. (If this makes no sense whatsoever to you, don't worry about it; just skip over this section for now.)

By default, no rules will fire while a query is being executed. If you want to allow backward chaining to occur in response to a query, you can use the max-background-rules declaration -- i.e.,
        (declare (max-background-rules 10))
would allow a maximum of 10 rules to fire while this particular query was being executed.

2.9.3. The run-query command

The run-query command lets you supply values for the external variables of a query and obtain a list of matches. This function returns a java.util.Iterator of jess.Token object, one for each matching combination of facts. The example code above calls fact(0) on each jess.Token, to get the first jess.Fact object from the jess.Token, then calls get(0) on the fact to get the data from the first slot (which for ordered facts, is a multislot named __data; see the documentation for jess.Fact) and then uses (nth$ 2)to get the second entry in that multislot.

Note that each token will contain one more fact than there are patterns on the query's LHS; this extra fact is used internally by Jess to execute the query.

You must supply exactly one value for each external variable of the named query.

2.9.4. The count-query-results command

To obtain just the number of matches for a query, you can use the count-query-results function. This function accepts the same arguments as run-query, but returns an integer, the number of matches.

2.9.5. The future of queries

defquery is a new feature, and the syntax may change; in particular, a simpler mechanism for obtaining query results may be defined. Suggestions are welcome.

2.10. Defmodules

A typical rule-based system can easily include hundreds of rules, and a large one can contain many thousands. Developing such a complex system can be a difficult task, and preventing such a multitude of rules from interfering with one another can be hard too.

You might hope to mitigate the problem by partitioning a rule base into manageable chunks. Modules let you divide rules and templates into distinct groups. The commands for listing constructs let you specify the name of a module, and can then operate on one module at a time. If you don't explicitly specify a module, these commands (and others) operate by default on the current module. If you don't explicitly define any modules, the current module is always the main module, which is named MAIN. All the constructs you've seen so far have been defined in MAIN, and therefore are often preceded by "MAIN::" when displayed by Jess.

Besides helping you to manage large numbers of rules, modules also provide a control mechanism: the rules in a module will fire only when that module has the focus, and only one module can be in focus at a time.

Note for CLIPS users: Jess's defmodule construct is similar to the CLIPS construct by the same name, but it is not identical. The syntax and the name resolution mechanism are simplified. The focus mechanism is much the same.

2.10.1. Defining constructs in modules

You can define a new module using the defmodule construct:
Jess> (defmodule WORK)

You can place a deftemplate, defrule, or deffacts into a specific module by qualifying the name of the construct with the module name:
Jess> (deftemplate WORK::job (slot salary))
  Jess> (list-deftemplates WORK)
    For a total of 1 deftemplates.

Once you have defined a module, it becomes the current module:
Jess> (get-current-module)
  Jess> (defmodule COMMUTE)
  Jess> (get-current-module)

If you don't specify a module, all deffacts, templates and rules you define will automatically become part of the current module:
Jess> (deftemplate bus (slot route-number))
  Jess> (defrule take-the-bus
  ?bus <- (bus (route-number 76))
  (get-on ?bus))
  Jess> (ppdefrule take-the-bus)
    "(defrule COMMUTE::take-the-bus
       ?bus <- (COMMUTE::bus (route-number 76))
       (get-on ?bus))"

You can set the current module explicitly using the set-current-module function. Note that the implied template have-correct-change was created in the COMMUTE module, because that's where the rule was defined.

2.10.2. Modules, scope, and name resolution

A module defines a namespace for templates and rules. This means that two different modules can each contain a rule with a given name without conflicting -- i.e., rules named MAIN::initialize and COMMUTE::initialize could be defined simultaneously and coexist in the same program. Similarly, the templates COMPUTER::bus and COMMUTE::bus could both be defined. Given this fact, there is the question of how Jess decides which template the definition of a rule or query is referring to.

When Jess is compiling a rule or deffacts definition, it will look for templates in three places, in order:
  1. If a pattern explicitly names a module, only that module is searched.
  2. If the pattern does not specify a module, then the module in which the rule is defined is searched first.
  3. If the template is not found in the rule's module, the module MAIN is searched last. Note that this makes the MAIN module a sort of global namespace for templates.
The following example illustrates each of these possibilities:
Jess> (assert (MAIN::mortgage-payment 2000))
  Jess> (defmodule WORK)
  Jess> (deftemplate job (slot salary))
  Jess> (defmodule HOME)
  Jess> (deftemplate hobby (slot name) (slot income))
  Jess> (defrule WORK::quit-job
    (job (salary ?s))
    (HOME::hobby (income ?i&:(> ?i (/ ?s 2))))
    (mortgage-payment ?m&:(< ?m ?i))
  Jess> (ppdefrule WORK::quit-job)
    "(defrule WORK::quit-job
     (WORK::job (salary ?s))
     (HOME::hobby (income ?i&:(> ?i (/ ?s 2))))
     (MAIN::mortgage-payment ?m&:(< ?m ?i))

In this example, three deftemplates are defined in three different modules: MAIN::mortgage-payment, WORK::job, and HOME::hobby. Jess finds the WORK::job template because the rule is defined in the WORK module. It finds the HOME::hobby template because it is explicitly qualified with the module name. And the MAIN::mortgage-payment template is found because the MAIN module is always searched as a last resort if no module name is specified.

Commands which accept the name of a construct as an argument (like ppdefrule, ppdeffacts, etc) will search for the named construct in the same way as is described above.

Note that many of the commands that list constructs (facts, list-deftemplates, rules, etc) accept a module name or "*" as an optional argument. If no argument is specified, these commands operate only on the current module. If a module name is given, they operate on the named module. If "*" is given, they operate on all modules.

2.10.3. Module focus and execution control

In the previous sections I described how modules provide a kind of namespace facility, allowing you to partition a rulebase into manageable chunks. Modules can also be used to control execution. In general, although any Jess rule can be activated at any time, only rules in the focus module will fire. Note that the focus module is independent from the current module discussed above.

Initially, the module MAIN has the focus:
Jess> (defmodule DRIVING)
  Jess> (defrule get-in-car
    (printout t "Ready to go!" crlf))
  Jess> (reset)
  Jess> (run)

In the example above, the rule doesn't fire because the DRIVING module doesn't have the focus. You can move the focus to another module using the focus function (which returns the name of the previous focus module:)
Jess> (focus DRIVING)
  Jess> (run)
    Ready to go!

Note that you can call focus from the right-hand-side of a rule to change the focus while the engine is running.

Jess actually maintains a focus stack containing an arbitrary number of modules. The focus module is, by definition, the module on top of the stack. When there are no more activated rules in the focus module, it is "popped" from the stack, and the next module underneath becomes the focus module. You also can manipulate the focus stack with the functions pop-focus, list-focus-stack, get-focus-stack, and clear-focus-stack.

The example program dilemma.clp shows a good use of modules for execution control. The auto-focus declaration
You can declare that a rule has the auto-focus property:
Jess> (defmodule PROBLEMS)
  Jess> (defrule crash
    (declare (auto-focus TRUE))
    (DRIVING::me ?location)
    (DRIVING::other-car ?location)
    (printout t "Crash!" crlf)
  Jess> (defrule DRIVING::travel
    ?me <- (me ?location)
    (printout t ".")
    (retract ?me)
    (assert (me (+ ?location 1))))
  Jess> (assert (me 1))
  Jess> (assert (other-car 4))
  Jess> (focus DRIVING)
  Jess> (run)

When an auto-focus rule is activated, the module it appears in is automatically pushed onto the focus stack and becomes the focus module. Modules with auto-focus rules make great "background tasks." Returning from a rule RHS
If the function
return is called from a rule's right-hand-side, it immediately terminates the execution of that rule's RHS. Furthermore, the current focus module is popped from the focus stack.

This suggests that you can call a module like a subroutine. You call the module from a rule's RHS using focus, and you return from the call using return.

Back to index