Search code examples
clipsexpert-systempyclips

Python function in LHS of CLIPS rule called multiple times - how to wait for a variable to contain a value?


I read here how to call a python function on the lhs of a clips rule.

Now I have the following rule:

(defrule python_func_lhs "comment me"
    (object (is-a clips_TEST_CLASS) (some_slot ?some_slot_value))
    (test (eq (python-call python_print (str-cat "some_slot: " ?some_slot_value)) TRUE))
    =>
    ;(assert (do_something))
)

My problem is that the python function is called twice, first printing

some_slot: nil

and then

some_slot: some_slot_value

It seems that the second rule part containing the python function does not "wait" for the first part of the LHS rule to be matched.

How can I make clips call the python function only one time, once the first part of the LHS rule is matched? In other words, I want to wait until the ?some_slot_value variable has a value.

If possible I would like to avoid creating several rules and using "control facts".


Solution

  • Different rule engines have different means of specifying when object changes are complete, but generally speaking when you make multiple distinct changes to an object, the pattern matching process will be invoked once for each change. You included a code fragment, not a reproducible example, in your question so I can only guess the cause of your issue, but probably what you're doing is creating the object and then modifying it in a separate step. Pattern matching is delayed when creating an object until all slot overrides have been processed and similarly when making object modifications you can use the modify-instance function to group a collection of slot changes as one change. If you need to delay pattern matching across several function calls, you can use the pattern-match-delay function.

    CLIPS> 
    (defclass clips_TEST_CLASS
       (is-a USER)
       (slot some_slot))
    CLIPS>    
    (definstances initial
       (i1 of clips_TEST_CLASS (some_slot some_slot_value)))   
    CLIPS> 
    (deffunction pcall (?v) (printout t ?v crlf) TRUE)
    CLIPS> 
    (defrule python_func_lhs 
        (object (is-a clips_TEST_CLASS) (some_slot ?some_slot_value))
        (test (pcall (str-cat "some_slot: " ?some_slot_value)))
        =>)
    CLIPS> (reset)
    some_slot: some_slot_value
    CLIPS> (make-instance i2 of clips_TEST_CLASS (some_slot some_other_value))
    some_slot: some_other_value
    [i2]
    CLIPS> (make-instance i3 of clips_TEST_CLASS)
    some_slot: nil
    [i3]
    CLIPS> (send [i3] put-some_slot another_value)
    some_slot: another_value
    another_value
    CLIPS> 
    (object-pattern-match-delay
       (make-instance i4 of clips_TEST_CLASS)
       (send [i4] put-some_slot still_another_value))
    some_slot: still_another_value
    still_another_value
    CLIPS> (modify-instance [i4] (some_slot value))
    some_slot: value
    TRUE
    CLIPS>