next up previous

5.4.1.3 Variables Single and Multifield

Wildcard symbols replace portions of a pattern and accept any value. The value of the field being replaced may be captured in a variable for comparison, display, or other manipulations. This is done by directly following the wildcard symbol with a variable name.

Syntax

Expanding on the syntax definition given in section 5.4.1.2 now gives:

<constraint> ::= <constant> | ? | $? |
                 <single-field-variable> |
                 <multifield-variable>
<single-field-variable> ::= ?<variable-symbol>
<multifield-variable>   ::= $?<variable-symbol>

where <variablesymbol> is similar to a symbol, except that it must start with an alphabetic character. Double quotes are not allowed as part of a variable name; i.e. a string cannot be used for a variable name. The rules for patternmatching are similar to those for wildcard symbols. On its first appearance, a variable acts just like a wildcard in that it will bind to any value in the field(s). However, later appearances of the variable require the field(s) to match the binding of the variable. The binding will only be true within the scope of the rule in which it occurs. Each rule has a private list of variable names with their associated values; thus, variables are local to a rule. Bound variables can be passed to external functions. The $ operator has special significance on the LHS as a patternmatching operator to indicate that zero or more fields need to be matched. In other places (such as the RHS of a rule), the $ in front of a variable indicates that sequence expansion should take place before calling the function. Thus, when passed as parameters in function calls (either on the LHS or RHS of a rule), multifield variables should not be preceded by the $ (unless sequence expansion is desired). All other uses of a multifield variable on the LHS of a rule, however, should use the $. It is illegal to use a multifield variable in a single field slot of a deftemplate/object pattern.

Example 1

CLIPS> (clear)
CLIPS> (reset)
CLIPS> (assert (data 2 blue green)
               (data 1 blue)
               (data 1 blue red))
<Fact-3>
CLIPS> (facts)
f-0     (initial-fact)
f-1     (data 2 blue green)
f-2     (data 1 blue)
f-3     (data 1 blue red)
For a total of 4 facts.
CLIPS>
(defrule find-data-1
  (data ?x ?y ?z)
  =>
  (printout t ?x " : " ?y " : " ?z crlf))
CLIPS> (run)
1 : blue : red
2 : blue : green
CLIPS>

Example 2

CLIPS> (reset)
CLIPS> (assert (data 1 blue)
               (data 1 blue red)
               (data 1 blue red 6.9))
<Fact-3>
CLIPS> (facts)
f-0     (initial-fact)
f-1     (data 1 blue)
f-2     (data 1 blue red)
f-3     (data 1 blue red 6.9)
For a total of 4 facts.
CLIPS>
(defrule find-data-1
  (data ?x $?y ?z)
  =>
  (printout t "?x = " ?x crlf
              "?y = " ?y crlf
              "?z = " ?z crlf
              "------" crlf))
CLIPS> (run)
?x = 1
?y = (blue red)
?z = 6.9
------
?x = 1
?y = (blue)
?z = red
------
?x = 1
?y = ()
?z = blue
------
CLIPS>

Once the initial binding of a variable occurs, all references to that variable have to match the value that the first binding matched. This applies to both single and multifield variables. It also applies across patterns.

Example 3

CLIPS> (clear)
CLIPS>
(deffacts data
  (data red green)
  (data purple blue)
  (data purple green)
  (data red blue green)
  (data purple blue green)
  (data purple blue brown))
CLIPS>
(defrule find-data-1
  (data red ?x)
  (data purple ?x)
  =>)
CLIPS>
(defrule find-data-2
  (data red $?x)
  (data purple $?x)
  =>)
CLIPS> (reset)
CLIPS> (facts)
f-0     (initial-fact)
f-1     (data red green)
f-2     (data purple blue)
f-3     (data purple green)
f-4     (data red blue green)
f-5     (data purple blue green)
f-6     (data purple blue brown)
For a total of 7 facts.
CLIPS> (agenda)
0      find-data-2: f-4,f-5
0      find-data-1: f-1,f-3
0      find-data-2: f-1,f-3
For a total of 3 activations.
CLIPS>


next up previous