Fork me on GitHub
#clara
<
2020-10-18
>
schmee14:10:15

are rule clauses order sensitive?

schmee14:10:06

i.e if I have

``````(defrule foo
[HighCardinality (= foo ?foo)]
[LowCardinality (= foo ?foo)]
=>
(insert! (->Foo ?name)))``````
does it matter for performance that `HighCardinality` is before `LowCardinality`?

ethanc17:10:59

I don't believe it would impact performance. The cartesian product would be the same size I believe

👍 3
schmee19:10:09

okay, this one has me completely stumped:

``````(defrecord Reachable [nodeType name])
(defrecord Node [nodeType area name])

(defrule area-reachability
[Reachable (= nodeType :area) (= name ?area)]
[Node (= area ?area) (= nodeType ?nodeType) (= name ?name)]
; [:not [Reachable (= nodeType ?nodeType) (= name ?name)]]
=>
(insert! (->Reachable ?nodeType ?name)))

(comment
(-> (mk-session [area-reachability])
(insert (->Reachable :area "World"))
(insert (->Node :room "World" "Foo"))
fire-rules))``````

schmee19:10:33

as written it finishes instantly, if you uncomment the `[:not ...]` it goes into an infinite loop

schmee19:10:26

the intent is to not insert the `Reachable` fact if it’s already in the session

mikerod19:10:32

It’s a commmon issue @schmee and you have to rethink the LHS to be in terms of what’s true about the entire state of the system

mikerod19:10:45

So with the :not above you are expressing a logical contradiction.

schmee19:10:33

I see, could you elaborate a bit?

schmee19:10:07

my mental model is that since the inserted node is not of `nodeType` `:area`, it will fail to match the first clause and hence the rule as a whole will not fire

schmee19:10:17

but that can’t be the case?

ethanc20:10:24

What Mkie is alluding to is clara's truth maintenance: http://www.clara-rules.org/docs/truthmaint/ With the `not` un-commented, the rule itself becomes a logical contradiction of itself. The rule will only execute and be considered true if the fact in question is not within the session. However, if the rule inserts a fact that itself asserts to be absent, then a loop would be formed. A base state would be a session without the fact in question, ergo the rule must insert the Fact. Then clara must assert that all truth has been maintained, and finds that the Fact is now present. Meaning that the Rule is no no longer true, thus a logical retraction occurs removing the Fact from the session. Then clara must asser that all truth has been maintained, again. However we are back to the base state meaning that there is no Fact within the session and the Rule is true again, thus the cycle repeats and continues forever. The wiki mentions ways to circumvent this mechanic using unconditional inserts, however these can lead to non-logical conclusions if assumptions are made.

schmee21:10:10

thanks @ethanc, that clears things up quite a bit! I’ll take some time to ponder that and see if I can write the rule differently

schmee21:10:01

I’m coming into Clara with a Datomic mindset, which will surely trip me up a few times before I understand the “rule engine way”

sparkofreason22:10:03

`insert-uncondtional!` is your friend here, if you want to have effects in the LHS of your rules. I find it easier to always use `insert!`, so that my rules are pure logic statements. When I want an effect, instead I insert a `request` fact, which is executed by some external component. That effect often invalidates the rule, thus causing the request to then be retracted by truth maintenance.

mikerod22:10:16

Yeah. I avoid unconditional in most cases.

mikerod22:10:01

You typically can phrase the problem in a way that works with TMS. Often intermediate facts and accumulators in an aggregate rule can solve common situations.