Search code examples
clips

How can I use a SYMBOL reference as modify argument?


I start doing a project in CLIPS and get a bit stuck.

I want to write a generic function to change values in template instances. This will be later used to define values from outside (CLIPS engine is running in a Qt Application and is passing settings via the WrapperDLL), without having special change functions for each slot.

Templates:

(deftemplate State
   (slot name (type SYMBOL))
   (slot update-function (type SYMBOL))
   (slot value (type NUMBER)))


(deftemplate Item
  (slot name)
  (slot value_to_change)
)

No I want to create a rule to update instances of Item based on the State:

(defrule set-value
    ?item <- (Item (name test)) 
    ?update-data-fact <- (State (name update-value)
                         (update-function ?update-function) 
                         (value ?value))
    =>
    (retract ?update-data-fact)
    ( modify ?item (?update-function ?value ))

)

If I now assert a new State, the value value_to_change of the selected Item should be changed:

(assert (State (name update-value) (update-function value_to_change) (value 10)))

This code leads to:

  Syntax Error: Check appropriate syntax for duplicate/modify function.

The problem is, that I cannot pass the name of the slot like this to the modify function. Is there a way to pass the slot name to a rule in this way?


Solution

  • Version 7.0 of CLIPS will support dynamically specifying the slot name in a modify statement, but you can't do this in CLIPS 6.4 and earlier versions. In 6.4, you can write a helper function that dynamically creates a string with the appropriate modify command and then evaluate that string:

             CLIPS (6.4.1 4/8/23)
    CLIPS> 
    (deffunction my-modify (?f ?s $?v)
       (if (fact-addressp ?f)
          then 
          (bind ?f (fact-index ?f)))
       (bind ?v (implode$ ?v))
       (bind ?string (str-cat
          "(modify " ?f " (" ?s " " ?v "))" ))
       (eval ?string))
    CLIPS> (deftemplate data (slot x) (multislot y))
    CLIPS> (watch facts)
    CLIPS> (assert (data (x 1) (y 2 3)))
    ==> f-1     (data (x 1) (y 2 3))
    <Fact-1>
    CLIPS> (my-modify 1 x 4)
    <== f-1     (data (x 1) ...)
    ==> f-1     (data (x 4) ...)
    <Fact-1>
    CLIPS> (my-modify 1 y "red" red 5)
    <== f-1     (data ... (y 2 3))
    ==> f-1     (data ... (y "red" red 5))
    <Fact-1>
    CLIPS>