CLIPS - templates and functions

In this short part, You will learn about about a deftemplate which stands for define template. This feature can aid You in writing rules whose patterns have a well-defined structure.

Deftemplate is analogous to a struct definition in C. It defines a grup of related fields in a pattern similar to the way in which a C struct is a group of related data. A deftemplate is a list of fields names slots. Deftemplate allows access by name rather than by specifying the order of fields.

A slot is a named single-slot or multi-slot. A single-slot contain exactly one field while a multi-slot contains zero or more fields. To write a slot, give the field name (attribute) followed by the field value. note that a multi-slot slot with one value is strictly not the same as a single-slot slot.

General form of deftemplate:

(deftemplate template-name
  (slot-1)
  (slot-2)
  ...
  (slot-n))

In a deftemplate, the attribute values may be specified more precisely than a simple value. In deftemplate may be specified a type of value.

Supported types:

  • SYMBOL
  • STRING
  • NUMBER
  • INTEGER
  • FLOAT

The field values can be specified by either explicitly listing them or giving a range of values:

  • allowed-symbols
  • allowed-strings
  • allowed-numbers
  • allowed-integers
  • allowed-floats
  • allowed-values

For numbers it is possible to define a range, for example (range 1900 2009) means years between 1900 and 2009.

For example:

(deftemplate yes-no-answer
  (slot answer
    (type SYMBOL)
    (allowed-symbols yes no)
    (default yes)))

Examine the code in CLIPS:

CLIPS> (deftemplate yes-no-answer
  (slot answer
    (type SYMBOL)
    (allowed-symbols yes no)
    (default yes)))
CLIPS> (assert (yes-no-answer (answer yes)))
<Fact-0>
CLIPS> (facts)
f-0     (yes-no-answer (answer yes))
For a total of 1 fact.
CLIPS> (assert (yes-no-answer (answer dont-know)))
 
[CSTRNCHK1] A literal slot value found in the assert command
does not match the allowed values for slot answer.

Now let's think how to store informations about book using deftemplate. For now, store only a title, author and the date of the book. Solution may look like following:

(deftemplate book
  (slot title
    (type STRING)
    (default "Unknown"))
  (slot author
    (type STRING)
    (default "Unknown"))
  (slot date
    (type INTEGER)
    (default 2001)
    (range 1600 2009)))

Now, we are able to assert new facts:

(assert (book (title "C++") (author "Stephen Prata") (date 2002)))

If we left blank one of field(for example title field) template will insert there default value. The (range 1600 2009) deny asserting books older than from 1600 and newest than 2009 (maybe they don't exist?).

In the source code we asserted two books of Stephen Prata. Write the rule to retract them from memory when (remove-pratas 1) fact is asserted. Simple solution:

(defrule remove-pratas "remove all Prata's books"
  (remove-pratas 1)
  ?which <- (book (title ?t) (author "Stephen Prata") (date ?d))
  =>
    (printout t "Removing book " ?t " from " ?d " year" crlf)
    (retract ?which))

Run the program now.

CLIPS> (load "books2.clp")
Defining deftemplate: book
Defining deffacts: books
Defining defrule: remove-pratas +j+j
TRUE
CLIPS> (reset)
CLIPS> (run)
CLIPS> (facts)
f-0     (initial-fact)
f-1     (book (title "Clisp book") (author "Giarratano") (date 2001))
f-2     (book (title "Common Lisp") (author "someone") (date 2005))
f-3     (book (title "C++") (author "Stephen Prata") (date 2002))
f-4     (book (title "ANSI C") (author "Stephen Prata") (date 2000))
For a total of 5 facts.
CLIPS> (assert (remove-pratas 1))
<Fact-5>
CLIPS> (run)
Removing book ANSI C from 2000 year
Removing book C++ from 2002 year

Download source code

But what, if we want to represent title of book not as a string but as a symbol? The solution is multi-slot.

(deftemplate book
  (multislot title
    (type SYMBOL)
    (default Unknown))
  (slot author
    (type STRING)
    (default "Unknown"))
  (slot date
    (type INTEGER)
    (default 2001)
    (range 1600 2009)))

Asserting facts looks the same as before, remember to do not use quotas:

(book (title C++) (author "Stephen Prata") (date 2002))

Try to write a rule similar to remove-pratas. Add a few books with the same word in title and then remove them from fact database. As a example verbose from remove-lords:

CLIPS> (reset)                                                                                                       
CLIPS> (facts)
f-0     (initial-fact)
f-1     (book (title Clisp book) (author "Giarratano") (date 2001))
f-2     (book (title Common Lisp) (author "someone") (date 2005))
f-3     (book (title C++) (author "Stephen Prata") (date 2002))
f-4     (book (title ANSI C) (author "Stephen Prata") (date 2000))
f-5     (book (title Lord of the rings the fellowship of the ring) (author "Tolkien") (date 2001))
f-6     (book (title Lord of the rings the two towers) (author "Tolkien") (date 2001))
f-7     (book (title Lord of the rings the return of the king) (author "Tolkien") (date 2001))
For a total of 8 facts.
CLIPS> (assert (remove-lords 1))                                                                                     
<Fact-8>                                                                                                             
CLIPS> (run)
Removing () Lord (of the rings the return of the king) book, author is Tolkien and the date is 2001
Removing () Lord (of the rings the two towers) book, author is Tolkien and the date is 2001
Removing () Lord (of the rings the fellowship of the ring) book, author is Tolkien and the date is 2001

Download source code

Defining functions

CLIPS allow You to define your own functions with deffunction

General syntax of a deffunction:

(deffunction <function-name> [optional comment]
  (?arg1 ?arg2 ... ?argM [$?argN]) ; last one may be optional multifield
  (<action 1>
   <action 2>
   ...
   <action K-1>
   <action K>) ; last action returns value

The names of arguments will not conflict with variable names in a rule if they are the same. The deffunction will only return the value of the last action; it may be a function, variable or a constant. Let's check simple example:

CLIPS> (deffunction my-fun (?a ?b) (- (* ?a ?a) (* ?b ?b)))
CLIPS> (defrule calc (numbers ?a ?b) =>(printout t "a^2 - b^2 = " (my-fun ?a ?b) crlf))
CLIPS> (assert (numbers 3 2)(numbers 25 16))
<Fact-1>
CLIPS> (run)
a^2 - b^2 = 369
a^2 - b^2 = 5

Deffunction may be used with multifield values:

CLIPS> (deffunction count-elements ($?to-count) (length $?to-count))
CLIPS> (count-elements 1 "one" 2 two 3 "three")
6
© Antoni Ligeza 2009 Driven by DokuWiki