0

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".

Community
  • 1
  • 1
langlauf.io
  • 3,009
  • 2
  • 28
  • 45
  • What has Jess got to do with this? – laune Sep 25 '15 at 14:29
  • @laune the question is not pyclips specific. In jess it should also be possible to call a java function on the lhs of a rule. But you are right, I will rephrase the question or delete the tag. – langlauf.io Sep 25 '15 at 14:56
  • I've just tried `(deffacts someData (Data (obj (new String "A"))))` and `(defrule find ?data <- (Data (obj ?a)) (test (eq (call ?a length) 1)) => (printout t "find executed" crlf))` in Jess and it works fine. – laune Sep 25 '15 at 15:55
  • @laune Thanks for the try. I am still investigating the issue and I _think_ the problem is this: "Test conditionals on the LHS of a rule are always evaluated when partial matches are being generated". I will try if using field constraints (& | ~ ) may be a solution. – langlauf.io Sep 25 '15 at 16:27
  • This may very well be a specific issue, depending on the implementation of the Rule Based System. CLIPS is just a family of dialects; rule engines are individual beasts. – laune Sep 25 '15 at 16:53

1 Answers1

2

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>
Gary Riley
  • 10,130
  • 2
  • 19
  • 34
  • Next time I will give a complete example. You spotted the problem correctly - thank you a low for sharing your clips know-how on SO – langlauf.io Sep 26 '15 at 11:50