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). 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 parses only simple floating point and integer numbers. It does not accept scientific or engineering notation. The following are all valid numbers:
 
  3 4. 5.643

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

2.1.5. Comments

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)
  5
  Jess> (+ (+ 2 3) (* 3 3))
  14
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)
  123
  Jess> ?a
  123

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)
  TRUE
  Jess> ?*x*
  3
  Jess> (bind ?*x* 4)
  4
  Jess> ?*x*
  4
  Jess> (reset)
  TRUE
  Jess> ?*x*
  3
  Jess> (bind ?*x* 4)
  4
  Jess> (set-reset-globals nil)
  FALSE
  Jess> (reset)
  TRUE  
  Jess> ?*x*
  4
You can read at 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>*)
     <expr>* 
    [<return-specifier>])
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)
    else
        (return ?b)))
  TRUE
Note that this could have also been written as:
  Jess> (deffunction max (?a ?b)
    (if (> ?a ?b) then
        ?a
     else
        ?b))
  TRUE
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)))
  TRUE
  Jess> (+ 2 2)
  5
This makes all additions equal to 1. By returning, the defadvice keeps the real function from ever being called.
  Jess> (defadvice before + (return 1))
  TRUE
  Jess> (+ 2 2)
  1
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)))
  TRUE
  Jess> (+ 2 2)
  3
  Jess> (undefadvice +)
  Jess> (+ 2 2)
  4

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))
  <External-Address:java.util.Hashtable>
  Jess> (call ?ht put "key1" "element1")
  Jess> (call ?ht put "key2" "element2")
  Jess> (call ?ht get "key1")
  "element1"
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))
  <External-Address:java.awt.Point>
  Jess> (set-member ?pt x 37)
  37
  Jess> (set-member ?pt y 42)
  42
  Jess> (get-member ?pt x)
  37
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)
  <External-Address:java.io.PrintStream>
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 fucntion that you can use explicitly.

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

Java type Jess type
A null reference The atom 'nil'
A void return value The atom 'nil'
String RU.STRING
An array A Jess multifield
boolean or java.lang.Boolean The atoms 'TRUE' and 'FALSE'
byte, short, int, or their wrappers RU.INTEGER
long or Long RU.LONG
double, float or their wrappers RU.FLOAT
char or java.lang.Character RU.ATOM
anything else RU.EXTERNAL_ADDRESS

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 type Possible Java types
RU.EXTERNAL_ADDRESS The wrapped object
The atom 'nil' A null reference
The atoms 'TRUE' or 'FALSE' java.lang.Boolean or boolean
RU.ATOM, RU.STRING String, char, java.lang.Character
RU.FLOAT float, double, and their wrappers
RU.INTEGER long, short, int, byte, char, and their wrappers
RU.LONG long, short, int, byte, char, and their wrappers
RU.LIST A 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)
  TRUE
  Jess> (assert (father-of danielle ejfried))
  <Fact-1>
  Jess> (facts)
  f-0   (initial-fact)
  f-1   (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 1)
  TRUE
  Jess> (facts)
  f-0   (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 mroe organization. In object-oriented languages, object 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 deftemplate. 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 deftemplate:
  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)))
  <Fact-0>
  Jess> (facts)
  f-0   (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 deftemplate.

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> (assert (box (location kitchen) (contents spatula sponge frying-pan)))
  <Fact-1>
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 1 (location dining-room))
  <Fact-2>
  Jess> (facts)
  f-0   (automobile (make Chrysler) (model LeBaron) (year 1997) (color white))
  f-2   (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 deftemplate 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))
  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.

Note that an ordered fact is very similar to an unordered fact with only one multislot. The similariety is so strong, that in fact this is how ordered facts are implemented in Jess. If you assert an unordered fact, Jess automatically generates a deftemplate for it. This generated deftemplate 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)))
  TRUE
  Jess> (reset)
  TRUE
  Jess> (facts)
  f-0   (initial-fact)
  f-1   (foo bar)
  f-2   (box (location garage) (contents scissors paper rock))
  f-3   (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 deftemplates that represent specific types of Java Beans. Jess can then use these deftemplates 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 deftemplate to represent a category of Beans, while definstance puts a representation of one specific Bean onto the knowledge base.

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

  public class ExampleBean
  {
    private String m_name = "Bob";
    public String getName() { return m_name; }
    public void setName(String s) { m_name = s; }
  }
C:\> java ExampleBean
This Bean has one property called "name". Before we can insert any of these Beans onto the knowledge base, we need a deftemplate to represent them: we must use defclass to tell Jess to generate it:
  Jess> (defclass simple ExampleBean)
  ExampleBean
  Jess> (ppdeftemplate simple)  
  (deftemplate simple extends __fact "$JAVA-OBJECT$ ExampleBean"
   (slot class (default <External-Address:jess.SerializablePropertyDescriptor>))
   (slot name (default <External-Address:jess.SerializablePropertyDescriptor>))
   (slot OBJECT (type 2048)))
This is a strange looking deftemplate, 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 deftemplate name.

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 objecte to the knowledge base.
  Jess> (bind ?sb (new ExampleBean))
  <External-Address:ExampleBean>
  Jess> (definstance simple ?sb static)
  <Fact-0>
  Jess> (facts)
  f-0   (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   (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)
  TRUE
  Jess> (facts)
  f-0   (initial-fact)
  f-1   (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 fulfil 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 Jess52/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 deftemplate'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.

2.8. Rules and Queries

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.

2.8.1. Defrules

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."
    (baby-is-wet)
    =>
    (change-baby))
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 (+ 2 2) 4) would evaluate to true. Instead, Jess will try to find a fact on the knowledge base that looks like (eq 4 4). 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)
  TRUE
  Jess>  (reset)
  ==> f-0 (initial-fact)
  TRUE
  Jess> (deffunction change-baby () (printout t "Baby is now dry" crlf))
  TRUE
  Jess> (defrule do-change-baby
      (baby-is-wet)
      =>
      (change-baby))
  do-change-baby: +1+1+1+t
  TRUE
  Jess>  (assert (baby-is-wet))
   ==> f-1 (baby-is-wet)
  ==> Activation: do-change-baby :  f-1
  <Fact-1>
Some of these diagnostics are interesting. We see first of all how issuing thereset 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+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: 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 file 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 do-change-baby f-1
  Baby is now dry
  1
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.

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.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))
  TRUE
  Jess> (assert (grocery-list eggs milk bacon))
  <Fact-0>
  Jess> (run)
  I need to buy (eggs milk bacon)
  1

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.1.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 assigned the fact ID of the particular fact that activated the rule.
2.8.1.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.1.4. 'Not' patterns.
A pattern can be enclosed in a list with not as the head. In this case, the pattern is considered to match if a fact 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 contain any variables that are not bound before that pattern (since a not pattern does not match any facts, it cannot be used to define the values of any variables!) You can use blank variables, however (a blank variable is a bare ? or $?). A not pattern can similarly not 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, 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.

not CEs can be nested to produce some interesting effects (see
the discussion of the exists CE).
2.8.1.5. The 'test' conditional element (CE).
A pattern with test as the head is special; the body consists not of a pattern to match against the knowledge base but of a single boolean function which is evaluated and whose truth determines whether the pattern matches. For example:
  Jess> (deftemplate person (slot age))
  Jess> (defrule example-8
     (person (age ?x))
     (test (> ?x 30))
     =>
     (printout t ?x " is over 30!" crlf))
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, 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.
2.8.1.6. The 'unique' conditional element.
A pattern can be enclosed in a list with unique as the head. This is a hint to Jess that only one fact could possibly satisfy a given pattern, given matches for the preceding patterns in that rule. Here's an example:
  Jess> (deftemplate tax-form (slot social-security-number))
  Jess> (deftemplate person (slot social-security-number) (slot name))
  Jess> (defrule unique-demo
   (tax-form (social-security-number ?num))
   (unique (person (social-security-number ?num) (name ?name)))
   =>
   (printout t "Auditing " ?name "..." crlf))
Here the unique CE is providing a hint to Jess that only one person can have a given Social Security number. Given this knowledge, Jess knows that once it has found the person that matches a given tax form, it doesn't need to look any further. In practice, this can result in performance gains of 20-30% on real problems.

unique may not be combined in the same patten with either test or not CEs.

Prolog users may recognize that unique is quite similar to that language's ! (cut) operator.
2.8.1.7. 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 ?m))
    =>
    (printout t ?m " is an 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.1.8. 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.1.9. 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)
Then you can define rules which match such patterns.
  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)
  TRUE
  Jess> (do-backward-chaining bar)
  TRUE
  Jess> (defrule rule-1
    (foo ?A ?B)
    =>
    (printout t foo crlf))
  TRUE
  Jess> (defrule create-foo
    (need-foo $?)
    (bar ?X ?Y)
    =>
    (assert (foo A B)))
  TRUE
  Jess> (defrule create-bar
    (need-bar $?)
    =>
    (assert (bar C D)))
  TRUE
  Jess> (reset)
  TRUE
  Jess> (run)
  foo
  3
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 cerate-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.8.2. Defqueries

The defquery construct lets you create a special kind of rule with no right-hand-side. While defrules act spontaneously, defqueries 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.Enumeration of all the matches. An example should make this clear. Suppose we have defined this defquery:
  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 ?e (run-query search blue))

     Jess> (while (?e hasMoreElements)
       (printout t (nth$ 2 (call (call (call ?e nextElement) fact 1) get 0)) crlf))
     red
     pink
     blue
     FALSE
because these three values follow blue in a foo fact. 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.

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                         
      r.reset();
      // Run the query, store the result
      r.executeCommand("(store RESULT (run-query search blue))");
      
      // Fetch the result (an Enumeration).
      Enumeration e = (Enumeration) r.fetch("RESULT").externalAddressValue(null);
      Vector v = new Vector(); 

      // Pick each element of the Enumeration apart and store the
      // interesting part in the Vector v.
      while (e.hasMoreElements())
      {
        Token t = (Token) e.nextElement();  

        // 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.
        v.addElement(multislot.get(1).stringValue(null));
      }
      for (Enumeration answers = v.elements(); answers.hasMoreElements();)
        System.out.println(answers.nextElement());
    }
  }
  C:\> java ExQuery
  
    red
    pink
    blue
  

Defqueries can use virtually all of the same features that rule LHSs can, except for salience. The function ppdefrule can also pretty-print defqueries.
2.8.2.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.8.2.2. 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.Enumeration 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.8.2.3. 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.8.2.4. 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.

Back to index