clara

http://www.clara-rules.org/
talgiat 2018-03-28T19:51:54.000241Z

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

2018-03-28T19:52:50.000546Z

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

2018-03-28T19:53:07.000656Z

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

2018-03-28T19:53:29.000175Z

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

talgiat 2018-03-28T19:53:55.000211Z

can you give an example?

2018-03-28T19:56:12.000517Z

here is one I made for unrelated reasons mostly https://gist.github.com/mrrodriguez/6a6f8373b25d69826b3efe154c928fac

2018-03-28T19:56:30.000023Z

I can probably do a shorter one in a min

talgiat 2018-03-28T19:57:35.000416Z

yeah this example is in response to my colleague

talgiat 2018-03-28T19:57:41.000641Z

we’re working on the same problem

talgiat 2018-03-28T19:58:07.000527Z

just seems kinda hackish

talgiat 2018-03-28T19:58:16.000353Z

also you need to know about the other rules

2018-03-28T19:58:38.000182Z

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

2018-03-28T19:58:44.000564Z

I see

2018-03-28T19:59:18.000742Z

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

talgiat 2018-03-28T19:59:20.000551Z

here is what we have

talgiat 2018-03-28T19:59:22.000319Z

`

talgiat 2018-03-28T19:59:23.000320Z

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

talgiat 2018-03-28T19:59:25.000392Z

`

talgiat 2018-03-28T19:59:37.000548Z

ignore the create rule-result

2018-03-28T19:59:41.000103Z

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

2018-03-28T20:00:13.000036Z

another thing you can do

2018-03-28T20:00:19.000677Z

Is let the :or fire as much as it can

2018-03-28T20:00:27.000412Z

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

talgiat 2018-03-28T20:00:38.000577Z

there is no best per se

talgiat 2018-03-28T20:00:47.000598Z

they are all equal importance

2018-03-28T20:01:00.000089Z

so what is the reason to want short-circuit

2018-03-28T20:01:14.000546Z

Do you just not want multiple facts inserted?

talgiat 2018-03-28T20:01:24.000526Z

`

talgiat 2018-03-28T20:01:31.000314Z

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

talgiat 2018-03-28T20:01:33.000844Z

I tried this

talgiat 2018-03-28T20:01:41.000560Z

but it went to an infinite loop

talgiat 2018-03-28T20:01:43.000544Z

not sure why

talgiat 2018-03-28T20:01:53.000332Z

yeah I just want one fact to be inserted

2018-03-28T20:02:18.000403Z

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

2018-03-28T20:02:23.000084Z

Insert a middle-fact

2018-03-28T20:02:30.000324Z

that you aggregate to a single fact

2018-03-28T20:02:36.000616Z

for “downstream” rules to only see 1 fact

2018-03-28T20:02:53.000349Z

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

2018-03-28T20:03:16.000311Z

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

2018-03-28T20:03:37.000123Z

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

2018-03-28T20:05:10.000414Z

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

2018-03-28T20:05:13.000245Z

logically

2018-03-28T20:05:21.000376Z

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

talgiat 2018-03-28T20:05:44.000650Z

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

2018-03-28T20:05:47.000549Z

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

2018-03-28T20:06:03.000082Z

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

2018-03-28T20:06:06.000751Z

so it’d be retracted

2018-03-28T20:06:29.000018Z

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

talgiat 2018-03-28T20:06:33.000515Z

I see

talgiat 2018-03-28T20:06:46.000186Z

yeah, a bit of a mind bender

talgiat 2018-03-28T20:06:48.000304Z

🙂

2018-03-28T20:06:57.000504Z

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

2018-03-28T20:07:00.000621Z

where possible

talgiat 2018-03-28T20:07:03.000295Z

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

2018-03-28T20:07:27.000485Z

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

2018-03-28T20:07:41.000682Z

It can be a trick sometimes

talgiat 2018-03-28T20:08:07.000461Z

the multiple inserts don’t impact our end results correctness

talgiat 2018-03-28T20:08:16.000224Z

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

talgiat 2018-03-28T20:08:27.000258Z

but thanks so much for the clarification

2018-03-28T20:09:34.000529Z

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

2018-03-28T20:09:50.000057Z

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

2018-03-28T20:09:55.000488Z

it lets you decide what makes sense there

2018-03-28T20:10:11.000097Z

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

2018-03-28T20:10:17.000463Z

to tie multiple rules together

talgiat 2018-03-28T20:10:54.000429Z

Yeah that makes sense

2018-03-28T20:11:14.000561Z

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

2018-03-28T20:11:27.000546Z

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

2018-03-28T20:11:47.000320Z

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

talgiat 2018-03-28T20:12:06.000658Z

yeah in our case it really doesn’t matter

2018-03-28T20:12:10.000410Z

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

2018-03-28T20:12:13.000772Z

sure

talgiat 2018-03-28T20:12:27.000620Z

but I see the point

2018-03-28T20:12:35.000140Z

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

talgiat 2018-03-28T20:12:42.000021Z

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

talgiat 2018-03-28T20:12:54.000039Z

instead of doing the heavy lifting yourself

talgiat 2018-03-28T20:13:02.000542Z

like a purposeful or

2018-03-28T20:13:26.000676Z

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

2018-03-28T20:13:39.000574Z

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

talgiat 2018-03-28T20:13:57.000269Z

true it can

2018-03-28T20:14:03.000174Z

Something like a “short circuit” or could be done

talgiat 2018-03-28T20:14:10.000440Z

but can’t I control which behavior I want

2018-03-28T20:14:12.000547Z

Easiest would be to just have it generate several rules

2018-03-28T20:14:19.000452Z

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

2018-03-28T20:14:33.000394Z

just generically

2018-03-28T20:15:53.000525Z

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

2018-03-28T20:16:07.000496Z

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

talgiat 2018-03-28T20:28:19.000407Z

Yeah, can do a macro

2018-03-28T20:35:51.000381Z

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)

➕ 2
2018-03-28T20:37:06.000353Z

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-dixon 2018-04-03T03:26:43.000115Z

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

2018-03-28T20:39:03.000730Z

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