You are on page 1of 4

CLIPS Tutorial 2 - Patterns and actions

Persistent facts
For the following exercises, you will need to use the same set of facts several times. Rather
than type them in repeatedly, you should use the deffacts structure. This is a way of
specifying facts which are recreated every time a (reset) is executed. For example, the
code

(deffacts startup (animal dog) (animal duck) (animal haddock))

will assert three facts onto the database every time the system is reset. Once they are
asserted, the facts are the same as any others - they can be retracted or used in rule
patterns - but even if they are retracted they will reappear after a (reset). Below is the list
of facts you will need to use - use the CLIPS editor to enter them in a deffacts structure
then reset CLIPS and look at the fact list to check that they are present.

(animal dog) (animal cat) (animal duck) (animal turtle) (warm-blooded dog)
(warm-blooded cat) (warm-blooded duck) (lays-eggs duck) (lays-eggs turtle)
(child-of dog puppy) (child-of cat kitten) (child-of turtle hatchling)

Matching things
So far, the patterns used to match rules against facts have been very simple and rather
restrictive. Each pattern has matched one specific fact. By using wildcards, it is possible to
make rules match multiple facts, executing their actions repeatedly. For instance, the rule:

(defrule animal
(animal ?)
=>
(printout t "animal found" crlf))

Produces the following results when run:

CLIPS>(run)
Animal found
Animal found
Animal found
Animal found
CLIPS>

Which shows that it has triggered four times, once for each fact matching
the (animal ?) pattern. In this pattern, the ? symbol is a wildcard. It will match any
symbol. You can use as many wildcards as you like in a pattern, but the first symbol may
not be one. So (child-of ? ?) is legal and will match four facts, but (? ? hatchling) is
illegal.

Variables in patterns

Page 1 of 4
Simple wildcards are only mildly useful. Variables make them indispensable. If we use
something like ?var instead of ? on its own, we can use the value of ?var each time the
rule is fired. Try this example:

(defrule list-animals
(animal ?name)
=>
(printout t ?name " found" crlf))

This will produce the following results:

CLIPS>(run)
turtle found
duck found
cat found
dog found
CLIPS>

The rule has matched four facts, and each time the variable ?name has taken the value of
the symbol it represents in the pattern, so that in the action part of the rule it can be
printed. The real power of this feature is apparent when two or more patterns are used, as
in the next example:

(defrule mammal
(animal ?name)
(warm-blooded ?name)
(not (lays-eggs ?name))
=>
(assert (mammal ?name))
(printout t ?name " is a mammal" crlf))

You may notice the not function sneaked in there. The purpose of this should be self-
evident. This rule gives the results

CLIPS>(run)
cat is a mammal
dog is a mammal
CLIPS>

When you are satisfied that you understand how this works, try the next step:

(defrule mammal2
(mammal ?name)
(child-of ?name ?young)
=>
(assert (mammal ?young))
(printout t ?young " is a mammal" crlf))

After you have run this rule, look at the fact list

CLIPS>(run)
kitten is a mammal

Page 2 of 4
puppy is a mammal
CLIPS>

Facts and rules


In order to retract a fact, you need to know its fact-index. You can retract facts from within
rules by binding them to variables, like this:

(defrule remove-mammals
?fact <- (mammal ?)
=>
(printout t "retracting " ?fact crlf)
(retract ?fact))

In the pattern part of this rule, the variable ?fact is given the fact-index of each fact
matching the pattern (mammal ?) in turn. That's what the leftwards arrow (<-) symbol
means. When you run it, this is what happens (the fact numbers may be different):

CLIPS>(run)
retracting <Fact-13>
retracting <Fact-14>
retracting <Fact-15>
retracting <Fact-16>
CLIPS>

All the mammal facts have been retracted.

Logic and Math Operators


You've already seen that two or more patterns in a rule are automatically connected with a
logical AND, which means that both must be true for the rule to fire. You've also seen
the not function, which leaves OR as the only boolean function missing for pattern
specification. CLIPS has an or function, which is used as shown:

(defrule take-umbrella
(or (weather raining)
(weather snowing))
=>
(assert (umbrella required)))

Which means "if it is raining or it is snowing, then take an umbrella". Notice the way
the or comes before the two arguments, rather than between them. this is known as prefix
notation, and all CLIPS operators work this way. For example, to express a sum of two
numbers in most computer languages, you would use something like 5 + 7 (this is known
as infix notation). In CLIPS, the expression would be written (+ 5 7). Examine the
following examples which show the addition, subtraction, multiplication and division
operators:

CLIPS>(+ 5 7)
12
CLIPS>(- 5 7)

Page 3 of 4
-2
CLIPS>(* 5 7)
35
CLIPS>(/ 5 7)
0.7142857142857143
CLIPS>

Rewrite the expression 10+4*19-35/12 in CLIPS notation and verify that you get the result
83.0833. (Answer at bottom of page).

Getting data from the user


CLIPS gets information from the user by means of the (read) function. Wherever (read) is
encountered, the program waits for the user to type something in, then substitutes that
response. To demonstrate this, type (assert (user-input (read))) at the CLIPS prompt.
After you press return, you'll need to type something else (anything) before the command
will complete. When you look at the facts, you'll see a new fact with your input as the
second item. Try the rule

(defrule what-is-child
(animal ?name)
(not (child-of ?name ?))
=>
(printout t "What do you call the child of a " ?name "?")
(assert (child-of ?name (read))))

When you run it, the system will now prompt you for the name of the young of any animal it
doesn't know about. It will use the data you enter to assert a fact, which could then be used
by other rules. In the car diagnostic example of the previous tutorial, you could have used a
rule such as

(defrule are-lights-working
(not (lights-working ?))
=>
(printout t "Are the car's lights working (yes or no)?")
(assert (lights-working (read))))

The correct CLIPS representation for the expression 10+4*19-35/12 is (+ 10 (- (* 4


19) (/ 35 12))).

Page 4 of 4

You might also like