Top Banner
Jess Basics
153
Welcome message from author
This document is posted to help you gain knowledge. Please leave a comment to let me know what you think about it! Share it to your friends and learn new things together.
Transcript
Page 1: JessBasics

Jess Basics

Page 2: JessBasics

Unpacking the Distribution Supplied as a single .zip file, used on all supported platform

Contains all that’s needed except for a JVM

Unpack to a folder Jess70p2\ containing

− README: Quick start guide

− LICENSE: Info about your rights

− bin\ : Contains a Windows batch file (jess.bat) and a UNIX shell script (jess) to start the Jess command prompt

− lib\: Contains Jess itself, as a Java archive file. Not "clickable" the JSR-94 (javax.rules) API in the file jsr94.jar

− docs\: index.html is the entry point for the Jess manual.

− examples\jess\: Small example programs.

− examples\xml\: Small example programs in JessML, Jess's XML rule language.

− eclipse\: JessDE, Jess's Integrated Development Environment, plugins for Eclipse 3.0 Documentation in Jess70p2/docs/eclipse.html

− src\ : source for Jess rule engine and development environment, including an Ant script

Page 3: JessBasics

Command-line Interface Go to the bin folder and execute jess.bat

C:\Program Files\Jess70p2\bin>jess

Jess, the Rule Engine for the Java Platform

Copyright (C) 2006 Sandia Corporation

Jess Version 7.0p1 12/21/2006

Jess>

Could also go just to Jess70p2:

C:\Program Files\Jess70p2>bin\jess

Evaluate a simple math expression (prefix)

Jess> (+ 2 3)

5

Jess>

Page 4: JessBasics

To execute a file of Jess code from the Jess prompt, use the batch command:

Jess> (batch "../examples/jess/sticks.clp")

Who moves first (Computer: c Human: h)?

Can execute this Jess program from the operating-system prompt

− Pass the name of the program as an argument to the Jess script

− Below, for variety, we go down only to the Jess70p2 folder

C:\Program Files\Jess70p2>bin\jess examples\jess\sticks.clp

Jess, the Rule Engine for the Java Platform

Copyright (C) 2006 Sandia Corporation

Jess Version 7.0p1 12/21/2006

Who moves first (Computer: c Human: h)?

Page 5: JessBasics

Class jess.Console is a simple graphical version of the Jess command-line interface.

C:\Program Files\Jess70p2>java -classpath lib\jess.jar jess.Console

Type expression

Then Enter

Page 6: JessBasics

3. Jess Language Basics Input to Jess is free-format

Newlines generally not significant

− Treated as whitespace

Page 7: JessBasics

3.1. Symbols A symbol is like an identifier in other languages

− Can contain letters, numbers, and any of $*=+/<>_?#

− Case sensitive

− May not begin with a number

− May begin with some punctuation marks Some have special meanings as operators at start of a symbol

Dashes are traditional word separators

Example valid symbols:

foo first-value contestant#1 _abc

3 "magic" symbols interpreted specially

− nil, akin to Java's null

− TRUE and FALSE

Page 8: JessBasics

3.2. Numbers Jess uses Java functions to parse numbers

The following are all valid numbers:

3 4. 5.643 5654L 6.0E4 1D

Page 9: JessBasics

3.3. Strings Character strings are denoted using "

\ used to escape embedded quote symbols

No escape sequences recognized

− E.g., can’t embed a newline in a string using "\n"

But real newlines are allowed inside a double-quoted string and become part of it

Some valid strings: "foo" "Hello, World" "\"Nonsense,\" he said firmly." "Hello,

There"

Page 10: JessBasics

3.4. Lists A list is (…) enclosing ≥ 0 symbols, numbers, strings, or other lists

− No commas between elements

E.g.:

(+ 3 2) (a b c) ("Hello, World") () (deftemplate foo (slot bar))

The 1st element of a list is its head

Page 11: JessBasics

3.5. Comments Jess supports 2 kinds comments:

− C-style block comments: /* … */

− Lisp-style line comments begin with a ; and go to the end of the line—e.g.,.

; This is a list

(a b c)

Comments can appear anywhere in a Jess program

Page 12: JessBasics

3.6. Calling Functions All code in Jess is in the form of a function call

− No operators

But some functions’ names are like Java operators

− Work like their Java counterparts

Function calls are lists using prefix notation—e.g.,

(+ 2 3)

Can nest function calls—e.g.,

Jess> (* (+ 1 2 3) (- 5 3))

12

Page 13: JessBasics

Can define your own functions in the Jess language and in Java

But many built-in functions

− Function printout sends text to Jess's standard output or to a file—e.g.,

Jess> (printout t "The answer is " (+ 12 15) "!" crlf)

The answer is 27!

− Function batch evaluates a file of Jess code—e.g.,

Jess> (batch "../examples/jess/hello.clp")

Hello, world!

− For details, see the Jess function guide, Jess70p2/docs/functions.html

Page 14: JessBasics

3.7. Variables Variables are identifiers beginning with ?

− Can contain letters, numbers, and the characters -, _, :, *

A variable can refer to a single symbol, number, or string, or to a list

Assign a value to a variable using function bind—e.g.,

Jess> (bind ?x 12)

12

Variables aren’t declared except for defglobals

To see the value of a variable, type it at the prompt—e.g.,

Jess> ?x

12

Page 15: JessBasics

3.7.1. Global Variables (or defglobals) Variables created

− at the Jess> prompt or

− at the top level of a Jess program

are cleared when reset is issued

To create global variables not destroyed by reset, use the defglobal construct

(defglobal [?<global-name> = <value>]+)

Global variable names begin (after the ?) and end with a *—e.g.,

?*a* ?*all-values* ?*counter*

When reset is issued, global variable may be reset to their initial values

− Depends on the current setting of the reset-globals property

− Function set-reset-globals sets this property

Page 16: JessBasics

Jess> (defglobal ?*x* = 3 ?*y* = 6)

TRUE

Jess> (bind ?*x* 4)

4

Jess> (reset)

TRUE

Jess> ?*x*

3

Jess> (set-reset-globals nil)

FALSE

Jess> (bind ?*x* 4)

4

Jess> (reset)

TRUE

Jess> ?*x*

4

Page 17: JessBasics

3.8. Control Flow Control flow, like everything in Jess, is done by function calls

Thus functions if, while, for, try

− Work like Java constructs with the same names

Also new function, e.g., foreach

Page 18: JessBasics

Iteration(while <expression> [do] <action>*)

Evaluates <expression>

If true, evaluates all <action> arguments

Repeats until <expression> evaluates to FALSE, then returns FALSE

File while.clp:

(bind ?i 3)

(while (> ?i 0)

(printout t ?i crlf)

(–- ?i)

)

Jess> (batch "../myExamples/while.clp")

3

2

1

FALSE

Page 19: JessBasics

(for <initializer> <condition> <increment> <action>*)

Like the Java construct

Loop continues until the condition is false or return is encountered

− (return) or (return <expression>)

In Java, the initializer, condition, or increment can be empty

− In Jess, use constant nil

Page 20: JessBasics

File for.clp:

(bind ?j 0)

(for (bind ?i 3) (> ?i 0) (-- ?i)

(printout t ?i crlf)

(++ ?j)

(printout t " " ?j crlf)

)

Jess> (batch "../myExamples/for.clp")

3

1

2

2

1

3

FALSE

Page 21: JessBasics

(foreach <variable> <list-expression> <action>*)

Set <variable> to each of the list elements in turn

Exit when the list is exhausted or return is encountered

File foreach.clp:

(foreach ?x (create$ a b c d)

(printout t ?x crlf)

)

Jess> (batch "../myExamples/foreach.clp")

a

b

c

d

Page 22: JessBasics

3.8.2. Decisions and Branching(if <expression> then <action>* [else <action>*])

The Boolean expression is evaluated

If it doesn’t evaluate to FALSE,

− the 1st list of actions is evaluated and

− the return value is what’s returned by the last action of the list

If the expression is FALSE and the else block is supplied, then

− the 2nd list of actions is evaluated and

− the value of the last is returned

The new Jess has an elif keyword

Page 23: JessBasics

File simple_if.clp:

(printout t "Enter an integer" crlf)

(bind ?x (read t))

(if (> ?x 100) then

(printout t "A big number" crlf)

(* ?x ?x)

)

Jess> (batch "../myExamples/simple_if.clp")

Enter an integer

101

A big number

10201

Page 24: JessBasics

File if_else.clp:

(printout t "Enter an integer" crlf)

(bind ?x (read t))

(if (> ?x 100) then

(printout t "A big number" crlf)

(* ?x ?x)

else

(printout t "A little number" crlf)

(sqrt ?x)

)

Jess> (batch "../myExamples/if_else.clp")

Enter an integer

49

A little number

7.0

Page 25: JessBasics

Get if-else if-else by nesting an if in the else clause

File if_elseif_else.clp:

(printout t "Enter an integer" crlf)

(bind ?x (read t))

(if (> ?x 100) then

(printout t "A big number" crlf)

(* ?x ?x)

else (if (> ?x 50) then

(printout t "A medium number" crlf)

(/ ?x 2)

else

(printout t "A little number" crlf)

(sqrt ?x)

)

)

Page 26: JessBasics

Jess> (batch "../myExamples/if_elseif_else.clp")

Enter an integer

80

A medium number

40.0

Page 27: JessBasics

4. Defining Functions in Jess4.1. Deffunctions

(deffunction <function-name> [<doc-comment>] (<parameter>*) <expr>* [<return-specifier>])

<function-name> must be a symbol

Each <parameter> must be a variable name

<doc-comment> is a double-quoted string describing the function

Any number of <expr> expressions

<return-specifier> gives the return value of the function

− Either an explicit return

− or any value or expression last encountered in executing the function

Control flow is achieved via control-flow functions

Page 28: JessBasics

(deffunction max

"Return the larger of 2 numerical arguments"

(?a ?b)

(if (> ?a ?b) then

(return ?a)

else

(return ?b))

)

Jess> (batch "myExamples/max.clp")

TRUE

Jess> (max 3 5)

5

Page 29: JessBasics

This program could also be written as

(deffunction max (?a ?b)

(if (> ?a ?b) then

?a

else

?b)

)

Page 30: JessBasics

For a deffunction taking any number of arguments, make the last formal parameter be a multifield: a variable with '$' before the ‘?’

− When the deffunction is called, the multifield variable contains a list all remaining arguments passed

− No more than one such wildcard argument

− The last argument to the function

(deffunction max ($?args)

(bind ?mx 0)

(foreach ?x $?args

(if (> ?x ?mx) then

(bind ?mx ?x) )

)

(return ?mx)

)

Jess> (batch "myExamples/max2.clp")

TRUE

Jess> (max 4 2 5 3)

5

Page 31: JessBasics

4.2. defadvice defadvice lets you wrap extra code around a Jess function so that

− either it executes before the real function to 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 to see the return value of the real function and possibly alter it

Lets add-on authors extend Jess without changing internal code

E.g., intercept calls to + and add an extra argument 1

− $?argv is a magic variable containing a list of the function name and the arguments of the call

Jess> (defadvice before + (bind $?argv (create$ $?argv 1)))

TRUE

Jess> (+ 1 2)

4

Page 32: JessBasics

E.g., keep the real function from being called, make all additions equal to 1

Jess> (defadvice before + (return 1))

TRUE

Jess> (+ 1 2)

1

E.g., subtract 1 from the return value of +

− ?retval is a magic variable; its value is the real function’s return value

Jess> (defadvice after + (return (- ?retval 1)))

TRUE

Jess> (+ 1 2)

2

undefadvice removes the advice

Jess> (undefadvice +)

TRUE

Jess> (+ 1 2)

3

Page 33: JessBasics

List Functionscreate$ or list Returns a list whose elements are its arguments

− If an argument is a list, its elements are included separately in the result

Jess> (bind ?list1 (create$ 1 2 3))

(1 2 3)

Jess> (create$ ?list1 4)

(1 2 3 4)

length$ Returns the length of its list argument

Jess> (length$ ?list1)

3

Page 34: JessBasics

first$ Takes a list argument, returns a list containing only the 1st element of it

Jess> (first$ ?list1)

(1)

rest$ Takes a list argument and returns a list of all its arguments but the 1st

Jess> (rest$ ?list1)

(2 3)

nth$ Takes and integer index and a list, returns the element at that index

− Jess list indices start at 1 (base-1)

Jess> (nth$ 2 ?list1)

2

Page 35: JessBasics

listp

Returns TRUE if its argument is a list

Jess> (listp ?list1)

TRUE

Jess> (listp 5)

FALSE

union$ Passed 1 or more lists, returns their union (concatenation with

duplicates removed)

Jess> (bind ?list2 (list 2 4 6))

(2 4 6)

Jess> (bind ?list3 (list 1 3 5))

(1 3 5)

Jess> (union$ ?list1 ?list2 ?list3)

(1 2 3 4 6 5)

Page 36: JessBasics

intersection$ Passed 1 or more lists, returns their union (list of elements in all)

Jess> (intersection$ ?list1 ?list2 ?list3)

(2)

Jess> (intersection$ ?list2 ?list3)

()

(member$ <expression> <list>) Returns the index of the value of the expression in the list or FALSE if

this value is not in the list.

− Note: A non-FALSE value generally counts as TRUE

Jess> (member$ 4 ?list2)

2

Jess> (member$ (+ 3 1) ?list2)

2

Jess> (member$ 5 ?list2)

FALSE

Page 37: JessBasics

(insert$ <list> <index> <single-or-list-expr>+) Returns a new list like the original but with 1 or more values inserted starting

at the index given

− A list is inserted as a sequence of the values it contains

Jess> (insert$ ?list1 2 5)

(1 5 2 3)

Jess> ?list1

(1 2 3)

Jess> (insert$ ?list1 4 ?list2)

(1 2 3 2 4 6)

To append an element,

Jess> (insert$ ?list1 (+ 1 (length$ ?list1)) 9)

(1 2 3 9)

To concatenate two lists,

Jess> (insert$ ?list1 (+ 1 (length$ ?list1)) ?list3)

(1 2 3 1 3 5)

Page 38: JessBasics

(delete$ <list > <begin-index> <end-index>) Returns a new list like the original but with the elements from the

beginning to the end index deleted

− To delete a single element, have the 2 indices equal

Jess> (bind ?list4 (list 2 4 6 8 10 12))

(2 4 6 8 10 12)

Jess> (delete$ ?list4 2 4)

(2 10 12)

Jess> (delete$ ?list4 2 2)

(2 6 8 10 12)

Jess> (delete$ ?list1 1 1)

(2 3)

Jess> (delete$ ?list1 2 (length$ ?list1))

(1)

Page 39: JessBasics

(replace$ <list> <begin-index> <end-index> <list>+) Returns a new list like the original but with

− the elements from the beginning to the end index

− replaced by the elements in the one or more lists at the end

Jess> (replace$ ?list4 2 4 (list 0 1 0))

(2 0 1 0 10 12)

Jess> (replace$ ?list4 2 4 (list 0 1 0) (list 1 0 1))

(2 0 1 0 1 0 1 10 12)

Jess> (replace$ ?list4 2 4 (list))

(2 10 12)

Page 40: JessBasics

Testing Equality (and other numerical relations) eq takes 2 or more arguments

− Returns TRUE if the 1st argument is equal in type and value to all subsequent arguments.

eq* also takes 2 or more arguments

− But returns TRUE if the 1st argument is merely equivalent to all the others—supports type conversion

= is like eq* but restricted to numerical values

neq if the negation of eq

− <> is the negation of =

− There is no neq*

Other numerical relations: <, <=, >, >=

Page 41: JessBasics

Jess> (bind ?lis ?list1)

(1 2 3)

Jess> (eq ?lis ?list1)

TRUE

Jess> (eq* ?list1 (list 1 2 3))

TRUE

Jess> (= 2 2.0)

TRUE

Jess> (eq* 2 2.0)

TRUE

Jess> (eq 2 2.0)

FALSE

Page 42: JessBasics

Arithmetic Operators+

− Add 1 or more numbers

*

− Multiply 1 or more numbers

-

− Passed 1 or more numbers, subtracts from the first all the rest

/

− Passed 1 or more numbers, divides the first by all the rest

Return value is a FLOAT

Jess> (/ 2)

2.0

Jess> (/ 16 4 2)

2.0

Page 43: JessBasics

mod− Passed 2 integers, returns remainder of dividing the 1st by the 2nd

**

− Takes 2 numbers, returns a FLOAT that’s the 1st raised to the 2nd

min

− Passed 1 or more numbers, returns the smallest

max

− Passed 1 or more numbers, returns the largest

Page 44: JessBasics

Auto-increment and –decrement(++ <variable>)

Increments the value of the variable (must be numerical), returns the result

(-- <variable>) Decrements the value of the variable (must be numerical), returns the

result

Page 45: JessBasics

Boolean Functionsnot Returns TRUE if it’s sole argument evaluates to FALSE

− Else returns FALSE

Jess> (not (< 3 2))

TRUE

and Returns TRUE if all its 1 or more arguments evaluate to a non-FALSE

value

− Else returns FALSE

Jess> (bind ?x 5)

5

Jess> (and (< 3 ?x) (< ?x 7))

TRUE

Page 46: JessBasics

or Returns TRUE if any of its 1 or more arguments evaluate to a non-

FALSE value

− Else returns FALSE

Jess> (or (< ?x 3) (< 7 ?x))

FALSE

Page 47: JessBasics

Functionals apply Returns result of calling the 1st argument, as a Jess function, on all

the remaining arguments

− 1st argument may be a variable whose value is the name (a string) of a Jess or user-defined function

Page 48: JessBasics

Jess> (bind ?op "+")

"+"

Jess> (apply ?op 5 2 1)

8

Jess> (bind ?op "-")

"-"

Jess> (apply ?op 5 2 1)

2

Jess> (deffunction inc2 (?x) (+ 2 ?x))

TRUE

Jess> (bind ?f_name "inc2")

"inc2"

Jess> (apply ?f_name 3)

5

Page 49: JessBasics

(map <function> <list>) Calls the function on each item in the list

− Returns a list of all the results

The function can be the name of a built-in or user-defined function

− Can also be a lambda expression (below)

Jess> (map "inc2" (list 1 2 3))

(3 4 5)

Jess> (map ?f_name (list 1 2 3))

(3 4 5)

Jess> (map "abs" (list -1 2 -3))

(1 2 3)

Page 50: JessBasics

lambda Used like deffunction to define a function

− But not given a name

Such an anonymous functions is useful if used only once, as with map

Jess> (map (lambda (?x) (+ 2 ?x)) ?list1)

(3 4 5)

Page 51: JessBasics

eval and build eval Its sole argument is a string whose content is Jess code

− The string is parsed, the expression evaluated, the result returned

Jess> (bind ?x "(length$ (list 1 2 3 4))")

"(length$ (list 1 2 3 4))"

Jess> (eval ?x)

4

build is a synonym for eval For historical reasons, build is generally used with rules, eval with

function calls

This functionality lets Jess create and incorporate new rules as it runs

− Essentially, it can learn

Page 52: JessBasics

Facts in JessManipulating the Working Memory

The watch and facts Functions

The working memory (or fact base) is a collection of facts (in the technical sense)

watch tells Jess to print messages when various interesting things happen

− Different arguments get Jess to report on different kinds of events

− (watch facts) gets Jess to report when facts are added or removed

Function reset initializes the working memory and creates fact

(MAIN::initial-fact)

Page 53: JessBasics

Jess signals

− addition of a fact with ==>

− removal of a fact with <==

unwatch reverses the effect of watch

Jess> (watch facts)

TRUE

Jess> (reset)

==> f-0 (MAIN::initial-fact)

TRUE

Jess> (unwatch facts)

TRUE

facts gets Jess to list all facts in the working memory

Jess> (facts)

f-0 (MAIN::initial-fact)

For a total of 1 facts in module MAIN

Page 54: JessBasics

Creating Facts with assert Add new facts to the working memory with assert

Jess> (reset)

TRUE

Jess> (assert (groceries milk eggs bread))

<Fact-1>

Jess> (facts)

f-0 (MAIN::initial-fact)

f-1 (MAIN::groceries milk eggs bread)

For a total of 2 facts in module MAIN.

A fact has a fact-id: here 0 and 1

− Lets you easily refer to the fact for changing or removing it

− Jess uses fact-ids when deciding the order for firing rules

Page 55: JessBasics

MAIN:: is the facts’ head, the current (default) module

− A module is a named collection rules, facts, and other constructs

assert takes one or more facts as arguments

− Returns the fact-id of the last asserted fact

− Or FALSE if the last fact couldn’t be asserted Usually because it’s a duplicate of a fact already in the

working memory

Page 56: JessBasics

Removing Facts with retract Remove an individual fact with retract, passing

− a numeric fact-id or

− an actual fact, i.e., a jess.Value object of type RU.FACT Holds a reference to a jess.Fact Java object

Function fact-id takes a fact-id and returns a Fact object

Jess> (fact-id 1)

<Fact-1>

Page 57: JessBasics

Jess> (retract 1)

TRUE

Jess> (facts)

f-0 (MAIN::initial-fact)

For a total of 1 facts in module MAIN.

Jess> (bind ?f (fact-id 0))

<Fact-0>

Jess> (retract ?f)

TRUE

Jess> (facts)

For a total of 0 facts in module MAIN.

Using fact-ids is easier when working interactively

− Using a reference (if you already have it) is faster for Jess

Page 58: JessBasics

Clearing and Initializing Working Memory

Working interactively, working memory fills up with irrelevant info

− And a running program periodically must restart from a known state

clear removes from working memory all facts

and variables, rules, and deffunctions

− Generally used only interactively

To restore the initial state without erasing entire application, use reset

− Puts working memory into a known state

− Includes at least initial fact (MAIN::initial-fact) Jess uses this fact internally Many rules don’t work without it

Before using working memory, issue reset

− Issue it again to reinitialize working memory

Page 59: JessBasics

The deffacts Construct A deffacts is a list of facts asserted into working memory when

reset is issued

− Can define any number of deffacts constructs

Jess> (clear)

TRUE

Jess> (deffacts catalog "Product catalog"

(product 354 sticky-notes "$1.99")

(product 355 paper-clips "$0.99")

(product 356 blue-pens "$2.99"))

TRUE

Jess> (facts)

For a total of 0 facts in module MAIN.

Continued

Page 60: JessBasics

Jess> (reset)

TRUE

Jess> (facts)

f-0 (MAIN::initial-fact)

f-1 (MAIN::product 354 sticky-notes "$1.99")

f-2 (MAIN::product 355 paper-clips "$0.99")

f-3 (MAIN::product 356 blue-pens "$2.99")

For a total of 4 facts in module MAIN.

Page 61: JessBasics

Kinds of Facts Working memory is like a relational DB

− Facts are like rows

3 kinds of facts

An unordered fact has named data fields like a DB tables’ columns

− Specify the slots in any order—e.g., (person (name “John Doe”) (age 34) (height 5 11) (weight 225))

− Most common kind of fact

An ordered fact is a flat list—e.g.,

(person “John Doe” 34 5 11 225)

− Convenient for simple bits of info

A shadow fact is an unordered fact linked to a Java object

− Lets us reason about events outside Jess

Page 62: JessBasics

Unordered FactsThe deftemplate Construct

Before asserting an unordered fact, use a deftemplate to define the slots for the kind of fact

Jess> (deftemplate person "People in actuarial database"

(slot name)

(slot age)

(slot gender))

TRUE

Jess> (assert (person (age 34) (name "Bill Jones")

(gender Male)))

<Fact-1>Continued

Page 63: JessBasics

Jess> (facts)

f-0 (MAIN::initial-fact)

f-1 (MAIN::person (name "Bill Jones") (age 34) (gender Male))

For a total of 2 facts in module MAIN.

The name of the deftemplate (here person) provides the head of the facts

Can omit slots in asserting an unordered fact

− Filled in using default values

Page 64: JessBasics

Default Slot Values Omitting a slot when asserting a fact, Jess provides a default value

− By default, it’s nil

Jess> (assert (person (age 30) (gender Female)))

<Fact-2>

Jess> (facts)

f-0 (MAIN::initial-fact)

f-1 (MAIN::person (name "Bill Jones") (age 34) (gender Male))

f-2 (MAIN::person (name nil) (age 30) (gender Female))

For a total of 3 facts in module MAIN.

If nil isn’t an acceptable default value, specify one with a slot qualifier

Page 65: JessBasics

Jess> (clear)

TRUE

Jess> (deftemplate person "People in actuarial database"

(slot name (default OCCUPANT))

(slot age)

(slot gender))

TRUE

Jess> (assert (person (age 30) (gender Female)))

<Fact-0>

Jess> (facts)

f-0 (MAIN::person (name OCCUPANT) (age 30) (gender Female))

For a total of 1 facts in module MAIN.

If default changes over time, in place of default, use default-dynamic

− Value then usually given by a function call E.g., for a timestamp,

(default-dynamic (time))

Page 66: JessBasics

Multislots Create a slot with a list of values with keyword multislot

Jess> (clear)

TRUE

Jess> (deftemplate person "People in actuarial database"

(slot name (default OCCUPANT))

(slot age)

(slot gender)

(multislot hobbies))

TRUE

Jess> (assert (person (name "Jane Doe") (age 22)

(hobbies skiing "collecting antiques")

(gender Female)))

<Fact-0>

The default default value for a multislot is nil

− Can specify a different default

Page 67: JessBasics

Changing Slot Values with modify Often a rule acts on a fact to change slot values

modify takes as its first argument a Fact object or a numeric fact-id

− All other arguments are slot/multislot name, value pairs

− It modifies the slots/multislots of the fact as per the given values

Jess> (modify 0 (age 23))

<Fact-0>

Jess> (facts)

f-0 (MAIN::person (name "Jane Doe") (age 23)

(gender Female)

(hobbies skiing "collecting antiques"))

For a total of 1 facts in module MAIN.

The fact-id of a modified fact isn’t changed

− A slot of one fact can hold the fact-id of another fact Build structures of related facts

Page 68: JessBasics

Copying Facts with duplicate duplicate is like modify but creates a new fact like the old but modified

as specified

− Returns the fact-id of the new fact

− or FALSE if no duplicate fact created

Jess> (duplicate 0 (name "John Doe") (gender Male))

<Fact-1>

Jess> (facts)

f-0 (MAIN::person (name "Jane Doe") (age 23)

(gender Female) (hobbies skiing “ collecting antiques"))

f-1 (MAIN::person (name "John Doe") (age 23)

(gender Male) (hobbies skiing "collecting antiques"))

For a total of 2 facts in module MAIN.

modify and duplicate require slot names as arguments

− Work only for unordered facts

Page 69: JessBasics

Ordered Facts Can assert ordered facts as long as no deftemplate using the same

head has been defined

Jess> (clear)

TRUE

Jess> (assert (number 123))

<Fact-0>

When you assert the 1st ordered fact with a given head, Jess generates an implied deftemplate for it

ppdeftemplate takes a fact head, returns the implied template as a string, embedded quotes escaped

Jess> (ppdeftemplate number)

"(deftemplate MAIN::number

\"(Implied)\"

(multislot __data))"

Ordered facts are unordered facts with a single multislot, __data

Page 70: JessBasics

show-deftemplates lists implied deftemplates along with explicitly created ones

Jess> (show-deftemplates)

(deftemplate MAIN::__clear

"(Implied)")

(deftemplate MAIN::__fact

"Parent template")

(deftemplate MAIN::__not_or_test_CE

"(Implied)")

(deftemplate MAIN::initial-fact

"(Implied)")

(deftemplate MAIN::number

"(Implied)"

(multislot __data))

FALSE

Note the 3 special templates used internally by Jess:

__clear, __fact, __not_or_test_CE

Page 71: JessBasics

Writing Rules in Jess The knowledge base is the collection of rules making up a rule-

based system

Rules take actions based on the contents of working memory

2 main classes of rules: forward-chaining and backward-chaining

Access working memory directly with queries

− Syntax similar to that of rules

− Search working memory, find specific facts, explore their relationships

Page 72: JessBasics

Forward-chaining Rules A rule’s then part can be executed whenever the if part is satisfied

Define a rule with the defrule construct

Simplest possible rule:

Jess> (defrule null-rule

"A rule that does nothing"

=>

)

TRUE

null-rule is the rule’s name

− If you define another rule named null-rule, original is deleted

− Also an undefrule to delete a rule by name

Page 73: JessBasics

Symbol => separates the rule’s LHS (if part) from its RHS (then part)

− null-rule has empty LHS and RHS Always executes, doing nothing

Two new arguments for watch:

− (watch activations) gets Jess to print a message when an activation record is placed on or removed from the agenda

An activation record associates a set of facts with a rule When the facts match the rule’s LHS, the rule should be

executed

(watch rules) gets Jess to print a message when a rules is fired

− I.e., when the actions on its RHS are executed

run tells Jess to start firing rules, returns number of rules fired

− Rule engine fires the rules on the agenda, one at a time, until the agenda’s empty

Page 74: JessBasics

Jess> (watch facts)

TRUE

Jess> (watch activations)

TRUE

Jess> (watch rules)

TRUE

Jess> (reset)

==> f-0 (MAIN::initial-fact)

==> Activation: MAIN::null-rule : f-0

TRUE

Jess> (run)

FIRE 1 MAIN::null-rule f-0

1

Since null-rule hasn’t a LHS, Jess makes it conditional on the presence of the initial fact

Page 75: JessBasics

Show that null-rule is conditional on (initial-fact) by calling ppdefrule on null-rule:

Jess> (ppdefrule null-rule)

"(defrule MAIN::null-rule

\"A rule that does nothing\"

(initial-fact)

=>)"

Page 76: JessBasics

A more complex rule:

Jess> (defrule change-baby-if-wet

"If baby is wet, change its diaper"

?wet <- (baby-is-wet)

=>

(change-baby)

(retract ?wet))

TRUE

LHS is a pattern (to match a fact in working memory), RHS is function calls

No function call on LHS

− Following doesn’t work

Jess> (defrule wrong-rule

(eq 1 1)

==>

(printout t “Just as I thought, 1 == 1!” crlf))

− Jess tries to find a fact (eq 1 1) in working memory

− To fire a rule based on evaluation of a function, use the test conditional element (later)

Page 77: JessBasics

(watch all) gets Jess to print info on everything important that happens while the program runs

Jess> (clear)

TRUE

Jess> (watch all)

TRUE

Jess> (reset)

==> Focus MAIN

==> f-0 (MAIN::initial-fact)

TRUE

Jess> (deffunction change-baby ()

(printout t "Baby is now dry" crlf))

TRUEContinued

Page 78: JessBasics

Jess> (defrule change-baby-if-wet

"If baby is wet, change its diaper"

?wet <- (baby-is-wet)

=>

(change-baby)

(retract ?wet))

MAIN::change-baby-if-wet: +1+1+1+t

TRUE

Jess> (assert (baby-is-wet))

==> f-1 (MAIN::baby-is-wet)

==> Activation: MAIN::change-baby-if-wet : f-1

<Fact-1>

Jess> (run)

FIRE 1 MAIN::change-baby-if-wet f-1

Baby is now dry

<== f-1 (MAIN::baby-is-wet)

<== Focus MAIN

1

How Jess interprets the rule internally

Store a reference to fact (baby-is-wet) in the pattern binding ?wet

All LHS conditions of the rule are met by this list of facts—just 1 here

Page 79: JessBasics

Rules not only react to the contents of working memory but also change it

− One run can put info into working memory causing another to fire

Nothing happens if we issue (run) again

− Jess activates a run only once for a given working memory state

− Don’t change baby again until a new baby-is-wet fact is asserted

Page 80: JessBasics

Constraining Slot Data Most patterns specify some set of slot values for the facts they match

− These specifications are constraints

Kinds of constraints

− Literal constraint: Exact slot value

− Variable constraint: Bind a matched value to a variable

− Connective constraint: Combine conditions to match A and B or A or B

− Predicate constraint: Call a function to test a match

− Return value constraint: Test for an exact match between a slot’s contents and the result of a function call

Page 81: JessBasics

Literal Constraints A pattern including a literal value matches only facts that include that value

Jess> (clear)

TRUE

Jess> (defrule literal-values

(letters b c)

=>)

TRUE

Jess> (watch activations)

TRUE

Jess> (assert (letters b d))

<Fact-0>

Jess> (assert (letters b c))

==> Activation: MAIN::literal-values : f-1

<Fact-1>

Page 82: JessBasics

Everything that applies to ordered facts applies to the multislots of unordered facts

− Likewise for the regular slots of unordered facts (but they hold only 1 value)

Matching literal constraints can’t convert types

− E.g., floating-point literal 1.0 doesn’t match integer 1

Page 83: JessBasics

Variables as Constraints Can use variables in place of literals for any part of the slot data

A variable matches any value in that position in the facts matching the pattern

− E.g., the following is activated each time an ordered fact with head a and 2 fields is asserted

Jess> (defrule simple-variables

(a ?x ?y)

=>

(printout t "'Saw 'a " ?x " " ?y "'" crlf))

Variables matched on the LHS of a rule are “input” for its RHS

You can mix literal values and variables in the same pattern

The same variable may occur in more than 1 pattern and more than once in a given pattern

− All occurrences must match the same value

Page 84: JessBasics

Jess> (defrule repeated-variables

(a ?x)

(b ?x)

=>

(printout t "?x is " ?x crlf))

TRUE

Jess> (watch activations)

TRUE

Jess> (deffacts repeated-variable-facts

(a 1)

(a 2)

(b 2)

(b 3))

TRUE

Jess> (reset)

==> Activation: MAIN::repeated-variables : f-2, f-3

TRUE

Jess> (run)

?x is 2

1

Page 85: JessBasics

Multifields A multifield matches 0 or more values

− Begins with ‘$?’—e.g., $?mf

− Used only in multislots

Can be used alone

Used with single values, a multifield expands to match all that’s not matched by other values

Page 86: JessBasics

E.g., the pattern in the following matches any shopping-cart fact with a contents slot containing milk

− preceded by 0 or more items and

− followed by 0 or more items

(defrule cart-containing-milk

(shopping-cart (contents $?before milk $?after))

=>

(printout t “The cart contains milk.” crlf))

A multifield contains the matched values as a (possibly empty) list

On the RHS, can (and should, for style) omit the ‘$’ since there the multifield acts as a normal variable

Page 87: JessBasics

Blank Variables ? is a wildcard, matching a field without binding a variable

− Used to specify that a multifield contains a certain arrangement of values

− E.g., (poker-hand ten ? ? ? ace)

$? is the wildcard for multifields

− Matches some or all the values—e.g.,

(shopping-cart (contents $? milk $?))

Page 88: JessBasics

Matching Globals Variables In, e.g., (score ?*x*), the match considers the value of the

defglobal when the fact is first asserted

Subsequent changes to the defglobal’s value don’t invalidate the match

Page 89: JessBasics

Connective Constraints In order of precedence:

~ (not)

& (and)

| (or)

Examples

− Match any client fact with a city slot not containing Bangor

(client (city ~Bangor))

− Match any client from Boston or Hartford

(client (city Boston|Hartford)

− Match any client not from Bangor but remember the city in ?c

(client (city ?x&~Bangor))

− Match any client from neither Bangor nor Portland:

(client (city ~Bangor&~Portland))

Page 90: JessBasics

No grouping symbols for constraints

− Can’t override precedence with (…)

If you can’t express what you want with connective constraints, use predicate constraints

Page 91: JessBasics

Constraining Matches with Predicate Functions

A predicate function is a Boolean function (returns TRUE or FALSE)

− Actually, any value except FALSE counts as TRUE

Use any predicate function as a constraint by preceding it with a ‘:’

To use a slot value as a function argument,

− bind the value to a variable then

− connect that binding to the function using &

Jess> (defrule small-order

(shopping-cart (customer-id ?id)

(contents $?c&:(< (length$ $?c) 5)))

(checking-out-now ?id)

=>

(printout t “Wouldn’t you like to buy more?” crlf))

Page 92: JessBasics

To express complex logical conditions, use not, and, or

Jess> (defrule large-order-and-no-dairy

(shopping-cart (customer-id ?id)

(contents $?c&

:(and (> (length$ $?c) 50)

(not (or (member$ milk $?c)

(member$ butter $?c))))))

(checking-out-now ?id)

=>

(printout t “Don’t you need dairy products?” crlf))

Page 93: JessBasics

Return Value Constraints Precede a function call in a slot with ‘=’

− The slot data then must match what the function returns

E.g., find a pair of items s.t. the price of the 1st is 2× that of the 2nd

(item (price ?x))

(item (price =(* ?x 2)))

− This is equivalent to

(item (price ?x))

(item (price ?y&:(eq ?y (* ?x 2))))

− Pretty-printing a rule transforms the former into the latter

Page 94: JessBasics

Pattern Bindings To use retract, modify, or duplicate on a fact matched by a

rule’s LHS, pass a handle to the fact to its RHS

− Use a pattern-binding variable

Jess> (defrule pattern-binding

?fact <- (a "retract me")

=>

(retract ?fact))

A reference to the jess.Fact object activating this rule is bound to ?fact when the rule is fired

− To retrieve the fact’s name, its integer ID, and other data, call the Java member functions of the jess.Fact class directly

Page 95: JessBasics

Jess> (defrule call-fact-methods

?fact <- (initial-fact)

=>

(printout t "Name is " (call ?fact getName) crlf)

(printout t "Id is " (call ?fact getFactId) crlf))

==> Activation: MAIN::call-fact-methods : f-0

TRUE

Jess> (reset)

==> Activation: MAIN::call-fact-methods : f-0

TRUE

Jess> (run)

Name is MAIN::initial-fact

Id is 0

1

Page 96: JessBasics

Pattern bindings must refer to specific facts

Need care when using them with the grouping conditional elements in the following sections

− Can’t use them with not or test conditional elements

− When using them with or and and conditional elements, make sure the binding applies to only 1 fact

Page 97: JessBasics

Qualifying Patterns with Conditional Elements

Conditional elements (CEs) are pattern modifiers

− Group patterns into logical structures

− Indicate the meaning of a match

Many conditional elements have same names as predicate functions

− But, e.g., the and predicate function works on Boolean expressions while the and CE works on patterns

− The context always distinguishes

Page 98: JessBasics

Jess’s conditional elements:

− and matches multiple facts

− or matches alternative facts

− not matches if no facts match

− exists matches if at least 1 fact matches

− test matches if a function call doesn’t evaluate to FALSE

− logical lets matching facts offer logical support to new facts

Page 99: JessBasics

The and Conditional Element Express the intersection of a group of patters using and

Jess> (defrule ready-to-fly

(and (flaps-up)

(engine-on))

=>)

But the entire LHS of any rule is enclosed in an implicit and

− So the and in the above rule isn’t needed

and is only of interest when used with other CEs

Page 100: JessBasics

The or Conditional Element Jess> (clear)

TRUE

Jess> (deftemplate used-car (slot price) (slot mileage))

TRUE

Jess> (deftemplate new-car (slot price)

(slot warrantyPeriod))

TRUE

Jess> (defrule might-buy-car

?candidate <- (or (used-car (mileage ?m&:(< ?m 50000)))

(new-car (price ?p&:(< ?p 20000))))

=>

(assert (candidate ?candidate)))

TRUEContinued

Page 101: JessBasics

Jess> (assert (new-car (price 18000)))

<Fact-0>

Jess> (assert (used-car (mileage 30000)))

<Fact-1>

Jess> (run)

2

Jess> (facts)

f-0 (MAIN::new-car (price 18000) (warrantyPeriod nil))

f-1 (MAIN::used-car (price nil) (mileage 30000))

f-2 (MAIN::candidate <Fact-1>)

f-3 (MAIN::candidate <Fact-0>)

For a total of 4 facts in module MAIN.

Page 102: JessBasics

Only 1 of the 2 branches of the or CE match at a time

− The rule can be activated as many times as there are facts to match

If the rule’s RHS tried to modify the mileage slot of the used-car template,

runtime errors would occur whenever ?candidate is bound to a new-car fact

The new-car template doesn’t have a mileage slot

If a rule’s RHS uses a variable defined by matching on the LHS

and the variable is defined by some but not all branches of an or pattern,

then a runtime error may occur

Page 103: JessBasics

and and or groups may be nested inside each other

− Jess rearranges the pattern so that there’s a single or at the top level—e.g.,

Jess> (defrule prepare-sandwich

(and (or (mustard) (mayo))

(bread))

=>)

TRUE

Jess> (ppdefrule prepare-sandwich)

"(defrule MAIN::prepare-sandwich

(or

(and

(mustard)

(bread))

(and

(mayo)

(bread)))

=>)"

Page 104: JessBasics

Subrule Generation and the or Conditional

Element A rule containing an or CE with n branches is equivalent to n rules,

each with 1 of the branches on its LHS

− This is how Jess implements the or conditional element

But Jess remembers the association of the created rules

− E.g., if the original rule is removed, all associated subrules are removed

Page 105: JessBasics

The not Conditional Element Most patterns can be enclosed in a list with not as the head

− Then the pattern matches if a fact (or set of facts) the enclosed patter is not found

E.g., the following fires if there are no cars at all or if there are only cars of colors other than red

Jess> (defrule no-red-cars

(not (auto (color red)))

=> )

− The pattern in the LHS here is not the same as

(auto (color ~red))

Page 106: JessBasics

Because a not pattern matches the absence of a fact,

it can’t define any variables used one the RHS or in subsequent patterns on the LHS

But variables can be introduced in a not pattern as long as they’re used in that pattern—e.g.,

Jess> (defrule no-odd-number

(not (number ?n&:(oddp ?n)))

=>

(printout t “There are no odd numbers.” crlf))

And a not pattern can’t have a pattern binding: it doesn’t match an actual fact

Page 107: JessBasics

We’ve seen that pattern matching is driven by facts being asserted

− The matching happens during the assert, definstance, modify, duplicate, or reset function call creating the fact

A not CE is evaluated in only 3 cases:

− When a fact matching what it encloses is asserted (the pattern match fails)

− When a fact matching what it encloses is removed ( the pattern match succeeds)

− When the pattern immediately before the non on the rule’s LHS is evaluated

Page 108: JessBasics

If a not CE is

− the 1st pattern on a rule’s LHS,

− the 1st pattern in an and group, or

− the 1st pattern on a given branch of an or group,

then the pattern (initial-fact) is inserted before the not to become the preceding pattern in question

So it’s important to issue (reset) before running the rule engine

The not CE can be used in arbitrary combination with the and and or CEs

− E.g., the following fires once and only once if, for every car of a given color, there’s a bus of the same color

Jess> (defrule forall-example

(not (and (car (color ?c)) (not (bus (color ?c)))))

=>)

Page 109: JessBasics

The exists Conditional Element The exists CE is shorthand for 2 nots nested one inside the

other

An exists CE is true if there exist any facts matching the enclosed pattern

It’s useful when you want a rule to fire only once even though there may be many facts that cold activate it

Jess> (defrule exists-an-honest-man

(exists (honest ?))

=>

(printout t ″There is at least 1 honest man.″ crlf))

Can’t bind any variables in an exists CE for later in the rule

Can’t use pattern bindings with exists

Page 110: JessBasics

The test Conditional Element The body of a test pattern isn’t a pattern to match against working

memory but a Boolean function

− It fails iff the function evaluates to FALSE

Jess> (deftemplate person (slot age))

TRUE

Jess> (defrule find-trusworthy-people-1

(person (age ?x))

(test (< ?x 30))

=>

(printout t ?x “ is under 30.” crlf))

A test CE can’t contain any variables not bound before it

It can’t have a pattern binding

Page 111: JessBasics

A test CE is evaluated every time the preceding rule on the LHS is evaluated (like not)

− So the following is equivalent to the preceding rule

Jess> (defrule find-trustworth-people-2

(person (age ?x&:(< ?x 30)))

=>

(printout t ?x “ is under 30.” crlf))

The test CE can also be used to write tests unrelated to facts

(import java.util.Date)

(defrule fire-next-century

(test ((newDate) after (new Date “Dec 31 2009)))

=>

(printout t “Welcome to the 22nd century!” crlf))

Page 112: JessBasics

Jess inserts the pattern (initial-fact) as a preceding pattern for the test when a test CE is

− the 1st pattern on the LHS,

− the 1st pattern in an and CE, or

− the 1st pattern in the branch of an or CE

Another reason for (reset)

Page 113: JessBasics

The logical Conditional Element Water flowing from a faucet has a logical dependency on the faucet

being open Jess> (defrule turn-water-on

(faucet open)

=>

(assert (water flowing))

TRUE

Jess> (defrule turn-water-off

(not (faucet open))

?water <- (water flowing)

=>

(retract ?water))

TRUE

Here (water flowing) logically depends on (faucet open)

Page 114: JessBasics

The logical CE lets you specify logical dependencies concisely

− All facts asserted on the RHS logically depend on any facts matching a pattern inside a logical CE on the LHS

− If any of the matches later become invalid, the dependent facts are retracted

Page 115: JessBasics

Jess> (clear)

TRUE

Jess> (defrule water-flows-while-faucet-is-open

(logical (faucet open))

=>

(assert (water flowing)))

TRUE

Jess> (assert (faucet open))

<Fact-0>

Jess> (run)

1

Jess> (facts)

f-0 (MAIN::faucet open)

f-1 (MAIN::water flowing)

For a total of 2 facts in module MAIN.

Continued

Page 116: JessBasics

Jess> (watch facts)

TRUE

Jess> (retract 0)

<== f-0 (MAIN::faucet open)

<== f-1 (MAIN::water flowing)

TRUE

Jess> (facts)

For a total of 0 facts in module MAIN.

Page 117: JessBasics

If fact 1 logically depends on fact 2, fact 1 receives logical support from fact 2

− A fact asserted without explicit logical support is unconditionally supported

A fact may receive logical support from multiple sources

− It isn’t retracted unless each of its logical supports is removed

If an unconditionally supported fact also receives explicit logical support, removing that support doesn’t cause the fact to be retracted

Page 118: JessBasics

Find a fact’s logical support with dependencies

− Find what it logically supports with dependents

Jess> (call (nth$ 1 (dependents 0)) getName)

"MAIN::water"

Jess> (call (call (nth$ 1 (dependencies 1)) fact 1) getName)

"MAIN::faucet"

Page 119: JessBasics

Backward-chaining Rules So far we’ve seen forward-chaining rules

In backward-chaining (goal seeking),

if the LHS is only partially matched

and the engine determines that firing some other rule would cause it to be fully matched,

then the engine tries to fire the 2nd rule

Jess’s backward chaining isn’t transparent to the programmer and is simulated with forward-chaining rules

Page 120: JessBasics

Sketch of the Example Use backward chaining to avoid computing the factorial of a number

more than once

The deftemplate factorial stores computed factorials—e.g., (factorial 5 125)

Rule print-factorial-10 has in its LHS (factorial 10 ?r1)

Register factorial for backward chaining so this pattern causes Jess to assert (need-factorial 10 nil)

There’s a do-factorial rule with LHS (need-factorial ?x ?) to compute the factorial of ?x and assert the result as a factorial fact

Page 121: JessBasics

To use backward chaining, first declare certain deftemplates as backward-chaining reactive

− Use function do-backward-chaining

Jess> (do-backward-chaining factorial)

TRUE

− If the template is unordered, must define it before this

Then may define rules with patterns matching corresponding facts

Jess> (defrule print-factorial-10

(factorial 10 ?r1)

=>

(printout t "The factorial of 10 is " ?r1 crlf))

TRUE

Page 122: JessBasics

Patterns that match backward-chaining reactive deftemplates are goals

If, after (reset), nothing matches the goal, a fact is inserted into working memory like

(need-factorial 10 nil)

− The fact’s head is constructed by adding need- to the goal’s head

− need-x facts are goal-seeking or trigger facts

Write a rule matching need-factorial trigger facts to compute and assert factorial facts

Page 123: JessBasics

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)))

TRUE

The rule compiler adds a negated match for the factorial pattern to the LHS

− So the rule doesn’t fire if the fact is already present

Page 124: JessBasics

Jess> (reset)

TRUE

Jess> (watch all)

TRUE

Jess> (run)

FIRE 1 MAIN::do-factorial f-1,

==> f-2 (MAIN::factorial 10 3628800)

==> Activation: MAIN::print-factorial-10 : f-0, f-2

FIRE 2 MAIN::print-factorial-10 f-0, f-2

The factorial of 10 is 3628800

<== Focus MAIN

Page 125: JessBasics

Managing the Agenda A rule is activated when its LHS matches working memory

− But it doesn’t fire immediately

The agenda is the list of activated but not-yet-fired rules

Conflict Resolution The set of activated rules eligible to be fired is the conflict set

Putting the rules in firing order is conflict resolution

The output of conflict resolution is the ordered list of activations, the agenda

− Function agenda shows this ordered list

Page 126: JessBasics

Jess’s conflict resolution is controlled by pluggable conflict-resolution strategies

Jess comes with 2:

− depth (default): fire most recently activated rule first

− breadth: fire in activation order

Function set-strategy changes the strategy—e.g., (set-strategy breadth)

The strategy often makes no difference, but sometimes it does

The depth strategy is intuitive and correct in most cases

− But has problems if every rule that fires activates another The oldest activations never get a chance to fire

But breadth can be confusing

Page 127: JessBasics

To write your own strategies in java, implement the jess.Strategy interface

− Then call set-strategy with the name of your class as the argument

The Strategy interface has a single non-trivial method, compare

− Compare 2 activations

− Return -1, 1, or 0 indicating 1st, 2nd, or either should fire 1st

Page 128: JessBasics

Changing Rule Priority with Salience Use rule salience to tell the conflict resolver to treat special rules

(e.g., ones reporting security breaches) specially

Each rule has a salience property giving its priority

− Rules with higher salience fire earlier Ties broken as determined by the strategy (as above)

− Default salience is 0

Use a salience declaration to set a rule’s salience

Jess> (defrule defer-exit-until-agenda-empty

(declare (salience -100))

(command exit-when-idle)

=>

(printout t “exiting …” crlf))

TRUE

Page 129: JessBasics

Specify salience using literal integers, global variables, or function calls

Current salience evaluation method determines how salience values are evaluated: 3 possible values:

− when-defined (default): fixed salience value computed when the rule’s defined

− when-activated: salience reevaluated each time the rule is activated

− every-cycle: salience of every rule on the agenda recomputed after every rule firing (computational expensive)

Query or set this method with functions get-salience-evaluation, set-salience-evaluation

Page 130: JessBasics

Extensive use of salience is discouraged

− Negative impact on performance

− Bad style in rule-based programming to force an order on rule firings

If you’re using more than 2 or 3 salience values, consider implementing your algorithm with deffunctions or Java

Page 131: JessBasics

Scripting Java with Jess Jess can be used as a kind of scripting language for Java

Examples To find out what a given API method does with a given argument,

it’s faster to start Jess and type one line of Jess code than to write, compile and run a small Java program

Or, to experiment with arrangements of a GUI,

create the graphical components with a few lines of Jess code then interactively assemble and arrange them

Page 132: JessBasics

Creating Java Objects Jess’s new function lets you create instances of Java classes

Jess> (import java.util.*)

TRUE

Jess> (bind ?prices (new HashMap))

<Java-Object:java.util.HashMap>

Like Java, Jess implicitly imports the entire java.lang package

− Can create Integer and String objects without explicitly importing that package

HashMap has a constructor that takes a Java int and a Java float as arguments

− You can invoke this in Jess, passing it normal Jess numbers

Jess> (bind ?prices (new HashMap 20 0.5))

<Java-Object:java.util.HashMap>

Page 133: JessBasics

When you call a Java method, Jess converts the arguments from Jess data types to Java types as per the following table

Jess type Possible Java types

RU.Java-Object The wrapped object

The symbol nil a null reference

The symbol TRUE or FALSE String, java.lang.Boolean, or boolean

RU.ATOM (a symbol), RU.STING String, char, or 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

Page 134: JessBasics

If an argument is passed to a Java constructor or method, Jess has

the java.lang.⟨Class⟩ object representing the formal parameter’s type

a jess.Value object containing the value passed

− It turns the Value’s contents into something assignable to the ⟨Class⟩

E.g., symbol TRUE can be passed to a function expecting a boolean argument or to one expecting a String argument

− The proper conversion is made in either case

Page 135: JessBasics

Calling Jess Methods Given a reference to a Java object in a Jess variable, you can invoke

any of the object’s methods using the call function

− The 1st argument to call is a Java object

− The 2nd argument is the name of the invoked method

− The remaining arguments are the arguments passed to the method

The arguments are converted as per the above table

E.g., use HashMap.put to associate some keys with values in our example, and HashMap.get to look up a value by key:

Jess> (call ?prices put bread 0.99)

Jess> (call ?prices put peas 1.99)

Jess> (call ?prices put beans 1.79)

Jess> (call ?prices get peas)

1.99

Page 136: JessBasics

Any Java method can be called this way except

− static methods

− methods returning or being passed arrays

− overloaded methods

Values returned by Java methods are converted to Jess types as per the following table

Java type Jess type

A null reference The symbol nil

A void return value The symbol nil

String RU.STRING

boolean or java.lang.Boolean The symbol TRUE or FALSE

byte, short, int, or their wrappers RU.INTEGER

long or java.lang.Long RU.LONG

double, float, or their wrappers RU.FLOAT

char or java.lang.Character RU.ATOM (a symbol)

An array A list

Anything else RU. Java-Object

Page 137: JessBasics

Nesting Function Calls, and a Shortcut When the 1st element of a function call is a Java object, Jess

assumes an implicit initial call

− Instead of

(call ?prices get beans)

can use simply

(?prices get beans)

This works even if the 1st element of a function call is another function call

− as long as it returns a Java objet—e.g.,

((bind ?prices (new HashMap) put bread 0.99)

Page 138: JessBasics

Calling Static Methods In both Java and Jess, can use the name of the Java class to

invoke its static methods—e.g.,

Jess> (call Thread sleep 1000)

Can’t omit call when calling a static method

− Most common use of call is to invoke static methods

Page 139: JessBasics

Calling set and get Methods JavaBeans are used for shadow facts in Jess

− Facts connecting working memory with the Java application in which Jess is running

One tool Jess includes for working with JavaBeans is a pair of methods to simplify accessing their data:

(set ⟨Java-Object⟩ ⟨property⟩ ⟨value⟩)

(get ⟨Java-Object⟩ ⟨property⟩)

− Alternatively,

(⟨Java-Object⟩ ⟨setter⟩ ⟨value⟩)

(⟨Java-Object⟩ ⟨getter⟩)

Page 140: JessBasics

Jess uses the JavaBeans convention for the names

− To derive the property name, take the Java method name Make the first letter uppercase ad the rest lower case

− For setters and getters, add “set” or “get” to the property name

Example Start with

Jess> (bind ?b (new javax.swing.JButton))

<Java-Object:javax.swing.JButton>

Using get and set

Jess> (set ?b text "Press me")

Jess> (get ?b text)

"Press me"

Equivalently, using a setter and a getter

Jess> (?b setText "Press Me")

Jess> (?b getText)

"Press me"

Page 141: JessBasics

Working with Arrays Jess automatically converts Java arrays to plain lists (Values of

type RU.LIST)—cf. the 2 tables above

E.g., call method keySet on our ?prices HashMap, then call method toArray on the result

− Jess converts the result to a list

Jess> (bind ?grocery-list ((?prices keySet) toArray))

("beans" "bread" "peas")

Page 142: JessBasics

To put the grocery list into a pop-up menu, pass the list as a constructor argument to the javax.swing.JComboBox class

− Expects an array, Jess converts

Jess> (import javax.swing.JComboBox)

TRUE

Jess> (bind ?jcb (new JComboBox ?grocery-list))

<Java-Object:javax.swing.JComboBox>

For big or multi-dimension arrays, stick to Java

Page 143: JessBasics

How Jess Chooses among Overloaded Methods

Jess is much less picky about data types than is Java

E.g., in Java, can’t store a float into a HashMap

− But can store a Jess float: converted to a java.lang.Double

A java method name is overloaded if there are multiple methods with that name for that class with different parameter lists

The Java compiler, faced with an overloaded methods name, chooses the most specific methods based on the parameter types

But Jess hasn’t the strict type info Java has

− It chooses the 1st overload it finds matching the parameter types

− So many ways to convert between Jess and Java values Notion of best match is too vague

Page 144: JessBasics

A set of overloaded methods usually do the same thing

− So overloading usually isn’t an issue

But sometimes you can’t get the overload you need

− Then use an explicit wrapper

E.g., a Java method is overloaded to take a boolean or String

− You want the boolean overload , but Jess calls the String one

− Create and pass a java.lang.Boolean object Converted by Jess to boolean

Page 145: JessBasics

Accessing Java Member Data Jess accesses public instance variables of Java objects using the

get-member and set-member functions

Jess> (bind ?pt (new java.awt.Point))

<Java-Object:java.awt.Point>

Jess> (set-member ?pt x 37)

37

Jess> (set-member ?pt y 42)

42

Jess> (get-member ?pt x)

37

Page 146: JessBasics

These functions also work with static (class) variables

− Use the name of the class instead of the object

Jess> (get-member System out)

<Java-Object:java.io.PrintStream>

Jess> ((get-member System out) println "Hi")

Hi

Jess> (get-member java.awt.BorderLayout NORTH)

"North"

Jess converts values for all kinds of member variables as it does with method arguments and return values

− Cf. the above tables

Page 147: JessBasics

Working with Exceptions When a Java method throws an exception (an object), Jess

catches it and makes it available

Jess also signals errors in your Jess code and in its own functions using exceptions

When Jess catches an exception, its default action is to print a message, including 1 or 2 stack traces

− If 1 trace, it shows where in Jess’s own Java code the problem occurred

− If the exception occurs in a Java method called from Jess, a second trace locates the error in that method

In deployed code, whenever you call a method that might throw an exception, supply a handler to execute a response

Page 148: JessBasics

The try function evaluates the expressions in its 1st block

If one throws an exception, that block is abandoned

− Evaluates expressions following the symbol catch (if it appears)

Optional finally block after the catch block

− Evaluated whether or not an exception is thrown

Jess> (deffunction parseInt (?String)

(try

(bind ?i (call Integer parseInt ?String))

(printout t "The answer is " ?i crlf)

catch

(printout t "Invalid argument" crlf)))

TRUE

Jess> (parseInt "10")

The answer is 10

Jess> (parseInt "1O")

Invalid argument

Page 149: JessBasics

A good use for finally is to close a file

Jess> (import java.io.*)

TRUE

Jess> (bind ?file nil)

Jess> (try

(bind ?file

(new BufferedReader

(new java.io.FileReader "C:/try.txt")))

(while (neq nil (bind ?line (?file readLine)))

(printout t ?line crlf))

catch

(printout t "Error processing file" crlf)

finally

(if (neq nil ?file) then

(?file close)))

The cat

sat on

the mat

FALSE

Page 150: JessBasics

Special variable ?ERROR is defined in every catch block

− It’s initialized by Jess to point to the caught exception

− Several methods can be called on it to get parts of the default message

Jess> (try (/ 2 "a") catch (bind ?ex ?ERROR))

<Java-Object:jess.JessException>

Jess> (?ex toString)

"Jess reported an error in routine Value.numericValue

while executing (/ 2 \"a\").

Message: '\"a\"' is a string, not a number."

Jess> (?ex getCause)

Jess> (?ex getContext)

"

while executing (/ 2 \"a\")"

Continued

Page 151: JessBasics

Jess> (?ex getData)

"a number"

Jess> (?ex getDetail)

"'\"a\"' is a string, not "

Jess> (?ex getLineNumber)

-1

Page 152: JessBasics

Function

(instanceof ⟨Java-Object⟩ ⟨Class⟩)

returns TRUE if ⟨Java-Object⟩ can be assigned to a variable whose type is ⟨Class⟩

− It’s implemented using java.lang.Class.isInstance()

Trivially, we have

Jess> (instanceof ?ex Exception)

TRUE

In Java, define multiple catch blocks, differentiated by exception type

− But only one catch block in Jess

− But can use

(instanceof ⟨Exception-Object⟩ ⟨Exception-Class⟩)

in multiple conditional branches

Page 153: JessBasics

Jess’s throw function throws Java exceptions from Jess code

− Works like throw in Java

− Its argument must be an extension of a Java class that extends java.lang.Throwable

Jess> (try

(throw (new Exception "This went wrong"))

catch

(printout t (call ?ERROR getDetail) crlf))

Exception thrown from Jess language code