Fork me on GitHub
#clara
<
2020-07-01
>
mac05:07:39

Is there an idiomatic way to do hierarchical rules in clara? I have a set of rules that all calculate the same property from a fact but I would like the calculation only to be made by the most specific of the rules that match. I have tried inserting a guard fact when a rule (e.g. [:not [:guard (= (:active this) true] and (insert! {:type guard :active true} ) matches and using salience to control firing order, but this results in an endless loop for reasons I cannot figure out.

mac10:07:04

As an example I don't understand why the code below goes into an endless loop.

(defrule test-rule
    "test guard"
    [:not [:guard (= (:active this) true)]]
    =>
    (do
      (println "Inserting guard!")
      (insert! {:type :guard :active true})))
  (-> (mk-session [test-rule]
                  :fact-type-fn :type)
      (fire-rules))

mikerod11:07:03

@mac use a different guard type for each tier

mikerod11:07:13

Where the rule never inserts it’s own type

mikerod11:07:08

@mac https://gist.github.com/mrrodriguez/6a6f8373b25d69826b3efe154c928fac this actually has a somewhat similar model as well. For a slightly different goal but notice the guarding not conditions

mac11:07:28

@mikerod Thanks, the gist looks very useful. Do you know why my example would loop?

mikerod11:07:38

@mac the rules attempt to find a logical consistency balance

mikerod11:07:54

Your rule Left side condition is invalidated when the right side inserts.

mikerod11:07:09

The engine then retracts that’s fact because it is no longer logically supported.

mikerod11:07:28

It’s called the truth maintenance system

mikerod11:07:59

Then it can activate again and re insert. And again it invalidates itself. So it’s logical looping

mac11:07:23

@mikerod OK, so the guard gets removed because the LHS match that caused it to be inserted no longer matches?

mikerod12:07:33

Think of rules not like in order. But instead that the rhs facts inserted are supported by the lhs

mac14:07:28

@mikerod Got it, this is much closer to logic programming than I thought, but it makes sense when framed like that.