Search code examples
clips

How to debug "Check appropriate syntax for defrule" in Clips rule engine?


(deftemplate illness
   (slot sickness)
   (multislot keywords))

(deffacts qestion-refrences
    (illness (sickness stunted-Groth)(keywords stunted groth))
    (illness (sickness pale-Yellow) (keywords pale yellow))
    (illness (sickness reddish-Brown)(keywords reddish brown))
    (illness (sickness stunted-Root)(keywords stunted root)))

(deffunction askquestion (?question)
    (printout t ?question)
    (bind ?answer (read))
    (if (lexemep ?answer) 
        then (bind ?answer (lowcase ?answer)))  
    ?answer)

(defrule determineSickness
    (bind ?f (askquestion "whot Does the plant seem to have ? "))
    (illness (keywords ?kw) (sickness ?sk))
    (while  (not (subsetp ?kw ?f )) 
        (bind ?f (askquestion "whot Does the plant seem to have ? ")))
=>   
    (assert ?sk))

What I am trying to do is simply ask the user what is wrong with their plant and using the keywords to identify the problem and then assert the problem. However I keep getting the following error.

Defining defrule: determineSickness 
[PRNTUTIL2] Syntax Error:  Check appropriate syntax for defrule.

ERROR:
(defrule MAIN::determineSickness
   (bind ?f (
FALSE
CLIPS> 

Solution

  • There's a BNF specification of valid CLIPS syntax in the CLIPS Basic Programming Guide. A relevant portion for defrules is:

    <defrule-construct> ::=
       (defrule <rule-name> [<comment>] 
          [<declaration>]
          <conditional-element>*
          =>
          <action>*)
    
    <action> ::= <expression>
    
    <expression> ::= <constant> | <variable> | <function-call>
    
    <function-call> ::= (<function-name> <expression>*)
    
    <conditional-element> ::= 
       <pattern-CE> | 
       <assigned-pattern-CE> | 
       <not-CE> | 
       <and-CE> | 
       <or-CE> | 
       <logical-CE> |
       <test-CE> |
       <exists-CE> |
       <forall-CE>
    

    The when portion of the rule (the part before the =>) consists of conditions that must be matched by facts/instances in order for the rule to be applicable. You can make function calls from the conditions of the rule, but not using the syntax you've attempted. In addition, since conditions can be activated in a non-sequential order, procedural code that must be executed sequentially needs to be specified in the actions of the rule (the part after the =>).

    You can make your original code syntactically correct with a few changes:

    (defrule determineSickness
        (illness (keywords $?kw) (sickness ?sk))
    =>
        (bind ?f (askquestion "whot Does the plant seem to have ? "))
        (while  (not (member$ ?f ?kw)) 
            (bind ?f (askquestion "whot Does the plant seem to have ? ")))
        (assert (diagnosis ?sk)))
    

    Your rule(s) are still semantically incorrect. This is what they currently do:

    For every illness, ask the user to specify one of the symptoms for that illness.
    

    This is what they need to do:

    For every symptom specified by the user, find every illness having that symptom.