Is there a way to have a short circuiting :or in clara, not sure why it is designed that way
@talgiat they aren’t meant for that. They are mostly just syntax sugar for multiple rules
In the case of you were sharing the stuff around the :or
(prior conditions) and the RHS
you can implement a “short circuit ” pattern via multiple rules by making rules that are prioritized over one another
can you give an example?
here is one I made for unrelated reasons mostly https://gist.github.com/mrrodriguez/6a6f8373b25d69826b3efe154c928fac
I can probably do a shorter one in a min
yeah this example is in response to my colleague
we’re working on the same problem
just seems kinda hackish
also you need to know about the other rules
(r/defrule short-circuit
[X] ;; whatever here
=>
(r/insert! <your fact here>
:rule-marker/short-circuit))
(defrule fallback
[:not [:rule-marker/short-circuit]]
[Y]
=>
(r/insert! <your fact here>))
I see
I don’t know that I see it as hackish. I do understand it could be brittle to more rules added
here is what we have
`
(defrule premium-video [Video (= ?id id)] [:or [PremiumChannels (= id ?id)] [LessThanTwoHours (= id ?id)] [PremiumTopics (= id ?id)]] => (insert! (create-rule-result ->MarketplacePremiumVideoContent ?id (->Rule 1 “Premium Video” :points 6)))))
`
ignore the create rule-result
however a big short-circuiting :or
would also be just order dependent on all the logic pushed into it
another thing you can do
Is let the :or
fire as much as it can
then reconcile in a separate rule to “choose the best”
there is no best per se
they are all equal importance
so what is the reason to want short-circuit
Do you just not want multiple facts inserted?
`
(defrule premium-video
[Video (= ?id id)]
[:not [MarketplacePremiumVideoContent (= id ?id)]]
[:or
[PremiumChannels (= id ?id)]
[LessThanTwoHours (= id ?id)]
[PremiumTopics (= id ?id)]]
=>
(insert! (create-rule-result ->MarketplacePremiumVideoContent ?id (->Rule 1 "Premium Video" :points 6)))))
I tried this
but it went to an infinite loop
not sure why
yeah I just want one fact to be inserted
(r/defrule rule-with-or
[:or
[A]
[B]
[C]]
=>
(r/insert! (->FoundIt)))
(r/defrule aggregate-found
[?found <- (acc/all) :from [FoundIt]]
[:test (seq ?found)]
=>
(r/insert! (do-aggregation ?found)))
Insert a middle-fact
that you aggregate to a single fact
for “downstream” rules to only see 1 fact
this can be either a merge
or just pick one if they are all the same, etc
(r/defrule aggregate-found
[?found <- (acc/all) :from [FoundIt]]
[:test (seq ?found)]
=>
;; They are all the same, so I dont' care
(r/insert! (first ?found)))
I should add a non-empty check to just avoid useless fires
> but it went to an infinite loop I believe your rule is invalidating itself
logically
however, I don’t know for sure not knowing what create-rule-result
does
it just creates a record and adds some other metadata to it
if somehow the RHS (or later rule) leads to a MarketplacePremiumVideoContent
to be inserted with that ?id
then you’d get a loop
because it’d get inserted, which would make the :not
become false
so it’d be retracted
but then :not
would be true again, so it’d get reinserted, but then :not
would be false again, so it’d be retracted - and repeat
I see
yeah, a bit of a mind bender
🙂
it’s best to try to think of the rules as declarative and order-independent
where possible
at least for people who are not used to rule engines or logic programming
and their job is to bring working memory into a steady and logically consistent state with all of the LHS of all rules
It can be a trick sometimes
the multiple inserts don’t impact our end results correctness
I just noticed it when testing and didn’t understand why
but thanks so much for the clarification
yeah, I find the “aggregating” to one idea common
I think the main takeaway is that the rules don’t short-circuit or control “duplcates” for you
it lets you decide what makes sense there
I’d say though, don’t be afraid to introduce “intermediate facts”
to tie multiple rules together
Yeah that makes sense
So rule-with-multiple-duplicate-inserts-possible
and aggregate-the-duplicates
rules with an intermediate/ephemeral fact between the two
then most other “downstream” rules just take the aggregated selection fact
Later on, there may be more complex reasoning in the aggregate-the-duplicates
than just “take one”
yeah in our case it really doesn’t matter
if for example, they are no longer complete duplicates, or perhaps you want to count how many times it was “true” by counting the duplicates
sure
but I see the point
It’s been discussed before to have a working-memory-as-a-set sort of Clara mode
I just think it’ll helpful to have a real or
instead of doing the heavy lifting yourself
like a purposeful or
where there were never duplicates inserted, etc. Drools does that by default with logical insert (managed by truth maintenance). However, it does have a performance cost to manage a set for working memory (frequent hash code calculations etc) and also, it isn’t always what people want
sometimes “cardinality” of duplicate facts inserted can matter to the rule logic
true it can
Something like a “short circuit” or could be done
but can’t I control which behavior I want
Easiest would be to just have it generate several rules
that all do the “tiered” blocking pattern one one another
just generically
also, there is nothing stopping you from making a higher-level macro that did the short-circuit rule generation pattern to normal Clara rules
If you were sufficiently motivated and had enough places you foudn it useful hah
Yeah, can do a macro
Agreed on all @mikerod’s comments - I just wanted to mention that you don’t necessarily have to use a macro generating “defrule” calls, Clara can take rules as data structures if you prefer to go that way (easier in clj than cljs though)
It seems the infinite looping behavior has tripped a lot of people up - we should probably add a page to the http://clara-rules.org site on that somewhere. I’ve also logged an issue before to fail in that scenario analogously to StackOverflowException, just haven’t ever gotten around to it
May have seen this. Was the proposal for a max number of iterations per rule?
My personal mental model of rules is (I think similar to his) that when using truth maintenance they are like statements that “for each join of things in these sets, these other things must exist”. Declarative logic, like SQL or even Excel