Fork me on GitHub
#clara
<
2018-03-28
>
talgiat19:03:54

Is there a way to have a short circuiting :or in clara, not sure why it is designed that way

mikerod19:03:50

@talgiat they aren’t meant for that. They are mostly just syntax sugar for multiple rules

mikerod19:03:07

In the case of you were sharing the stuff around the :or (prior conditions) and the RHS

mikerod19:03:29

you can implement a “short circuit ” pattern via multiple rules by making rules that are prioritized over one another

talgiat19:03:55

can you give an example?

mikerod19:03:30

I can probably do a shorter one in a min

talgiat19:03:35

yeah this example is in response to my colleague

talgiat19:03:41

we’re working on the same problem

talgiat19:03:07

just seems kinda hackish

talgiat19:03:16

also you need to know about the other rules

mikerod19:03:38

(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>))

mikerod19:03:18

I don’t know that I see it as hackish. I do understand it could be brittle to more rules added

talgiat19:03:20

here is what we have

talgiat19:03:23

(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)))))

talgiat19:03:37

ignore the create rule-result

mikerod19:03:41

however a big short-circuiting :or would also be just order dependent on all the logic pushed into it

mikerod20:03:13

another thing you can do

mikerod20:03:19

Is let the :or fire as much as it can

mikerod20:03:27

then reconcile in a separate rule to “choose the best”

talgiat20:03:38

there is no best per se

talgiat20:03:47

they are all equal importance

mikerod20:03:00

so what is the reason to want short-circuit

mikerod20:03:14

Do you just not want multiple facts inserted?

talgiat20:03:31

(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)))))

talgiat20:03:33

I tried this

talgiat20:03:41

but it went to an infinite loop

talgiat20:03:43

not sure why

talgiat20:03:53

yeah I just want one fact to be inserted

mikerod20:03:18

(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)))

mikerod20:03:23

Insert a middle-fact

mikerod20:03:30

that you aggregate to a single fact

mikerod20:03:36

for “downstream” rules to only see 1 fact

mikerod20:03:53

this can be either a merge or just pick one if they are all the same, etc

mikerod20:03:16

(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)))

mikerod20:03:37

I should add a non-empty check to just avoid useless fires

mikerod20:03:10

> but it went to an infinite loop I believe your rule is invalidating itself

mikerod20:03:21

however, I don’t know for sure not knowing what create-rule-result does

talgiat20:03:44

it just creates a record and adds some other metadata to it

mikerod20:03:47

if somehow the RHS (or later rule) leads to a MarketplacePremiumVideoContent to be inserted with that ?id then you’d get a loop

mikerod20:03:03

because it’d get inserted, which would make the :not become false

mikerod20:03:06

so it’d be retracted

mikerod20:03:29

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

talgiat20:03:46

yeah, a bit of a mind bender

mikerod20:03:57

it’s best to try to think of the rules as declarative and order-independent

mikerod20:03:00

where possible

talgiat20:03:03

at least for people who are not used to rule engines or logic programming

mikerod20:03:27

and their job is to bring working memory into a steady and logically consistent state with all of the LHS of all rules

mikerod20:03:41

It can be a trick sometimes

talgiat20:03:07

the multiple inserts don’t impact our end results correctness

talgiat20:03:16

I just noticed it when testing and didn’t understand why

talgiat20:03:27

but thanks so much for the clarification

mikerod20:03:34

yeah, I find the “aggregating” to one idea common

mikerod20:03:50

I think the main takeaway is that the rules don’t short-circuit or control “duplcates” for you

mikerod20:03:55

it lets you decide what makes sense there

mikerod20:03:11

I’d say though, don’t be afraid to introduce “intermediate facts”

mikerod20:03:17

to tie multiple rules together

talgiat20:03:54

Yeah that makes sense

mikerod20:03:14

So rule-with-multiple-duplicate-inserts-possible and aggregate-the-duplicates rules with an intermediate/ephemeral fact between the two

mikerod20:03:27

then most other “downstream” rules just take the aggregated selection fact

mikerod20:03:47

Later on, there may be more complex reasoning in the aggregate-the-duplicates than just “take one”

talgiat20:03:06

yeah in our case it really doesn’t matter

mikerod20:03:10

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

talgiat20:03:27

but I see the point

mikerod20:03:35

It’s been discussed before to have a working-memory-as-a-set sort of Clara mode

talgiat20:03:42

I just think it’ll helpful to have a real or

talgiat20:03:54

instead of doing the heavy lifting yourself

talgiat20:03:02

like a purposeful or

mikerod20:03:26

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

mikerod20:03:39

sometimes “cardinality” of duplicate facts inserted can matter to the rule logic

talgiat20:03:57

true it can

mikerod20:03:03

Something like a “short circuit” or could be done

talgiat20:03:10

but can’t I control which behavior I want

mikerod20:03:12

Easiest would be to just have it generate several rules

mikerod20:03:19

that all do the “tiered” blocking pattern one one another

mikerod20:03:33

just generically

mikerod20:03:53

also, there is nothing stopping you from making a higher-level macro that did the short-circuit rule generation pattern to normal Clara rules

mikerod20:03:07

If you were sufficiently motivated and had enough places you foudn it useful hah

talgiat20:03:19

Yeah, can do a macro

wparker20:03:51

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)

wparker20:03:06

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

alex-dixon03:04:43

May have seen this. Was the proposal for a max number of iterations per rule?

wparker20:03:03

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