Search code examples
clipsexpert-system

CLIPS deftemplate incorrect slot type


I am very puzzled by CLIPS. I have defined in a .clp file a deftemplate and a rule.

(deftemplate basic-ch "Basic characteristics template"
    (slot ch-name
        (type SYMBOL)
        (default ?DERIVE)
    )
    (slot score
        (type INTEGER)
        (default 1)
        (range 1 5)
    )
)
(defrule make-ch
    ?get-ch <- (get-ch TRUE)
    =>
    (printout t "Enter ch name" crlf)
    (bind ?name (read))
    (printout t "Enter ch score" crlf)
    (bind ?score (read))
    (assert (basic-ch (ch-name ?name) (score ?score)))
    (retract ?get-ch)
)

When i (assert (get-ch TRUE)) and (run), it prompts me for the ch name and score. However, if I enter a string for the score, the string score gets asserted by the rule! For example:

Enter ch name
hello
Enter ch score
hello
;(basic-ch (ch-name hello)(score hello)) get asserted?!

How is this possible? I have defined the score to be INTEGER and even provided the range. How can I stop this?


Solution

  • From Section 11, Constraint Attributes, of the Basic Programming Guide:

    Two types of constraint checking are supported: static and dynamic. When static constraint checking is enabled, constraint violations are checked when function calls and constructs are parsed. This includes constraint checking between patterns on the LHS of a rule when variables are used in more than one slot. When dynamic constraint checking is enabled, newly created data objects (such as deftemplate facts and instances) have their slot values checked for constraint violations. Essentially, static constraint checking occurs when a CLIPS program is loaded and dynamic constraint checking occurs when a CLIPS program is running. By default, static constraint checking is enabled and dynamic constraint checking is disabled. The default behavior can be changed by using the set-static-constraint-checking and set-dynamic-constraint-checking functions.

    If you enable dynamic constraint checking, you'll get an error when you run your program:

    CLIPS> (set-dynamic-constraint-checking TRUE)
    TRUE
    CLIPS> (assert (get-ch TRUE))
    <Fact-1>
    CLIPS> (run)
    Enter ch name
    hello
    Enter ch score
    hello
    
    [CSTRNCHK1] Slot value hello found in fact f-2     
    does not match the allowed types for slot score.
    [PRCCODE4] Execution halted during the actions of defrule make-ch.
    CLIPS> 
    

    Because it generates an error, dynamic constraint checking is useful for testing, but not for validating user input while a program is executing. If you want to validate use input, define some utility methods:

    CLIPS> 
    (defmethod get-integer ((?query STRING))
       (bind ?value FALSE)
       (while (not (integerp ?value))
          (printout t ?query " ")
          (bind ?value (read)))
       ?value)
    CLIPS>  
    (defmethod get-integer ((?query STRING) (?lower INTEGER) (?upper INTEGER))
       (bind ?value FALSE)
       (while (or (not (integerp ?value)) (< ?value ?lower) (> ?value ?upper))
          (printout t ?query " (" ?lower " - " ?upper ") ")
          (bind ?value (read)))
       ?value)
    CLIPS> (get-integer "Pick an integer:")
    Pick an integer: hello
    Pick an integer: 3
    3
    CLIPS> (get-integer "Pick an integer" 1 5)
    Pick an integer (1 - 5) -1
    Pick an integer (1 - 5) hello
    Pick an integer (1 - 5) 8
    Pick an integer (1 - 5) 4
    4
    CLIPS>