Fork me on GitHub
#clara
<
2018-01-12
>
alex-dixon00:01:14

Do any changes proposed in https://github.com/cerner/clara-rules/issues/373 affect short circuiting the evaluation of all LHS conditions? My understanding is that if the first condition doesn’t match the remaining ones are still processed

mikerod13:01:36

@alex-dixon right now the alpha network is “eagerly” evaluated

mikerod13:01:47

So constraints within conditions that are independent of a join with another condition

mikerod13:01:00

Clara has had this sort of “re-ordering” property since way back (maybe always) now. The discusses we have had before about trying to be “lazier” in evaluation by not evaluating any part of a condition if the prior conditions were satisfied, would be affected by this re-ordering logic

alex-dixon17:01:46

Thanks. Printed out ch 2 of the paper you recommended. It’s awesome. Working my way through. Will try to avoid asking you to explain rete to me in the interim:blush: That said: If Clara’s reordering doesn’t honor the order of conditions in the lhs as they are written (even if just for alphas) would any of the changes in @wparker ‘s proposal make it so the developer’s ordering is honored when evaluating a lhs? My understanding is that’s part of the proposal, but only for Boolean conditions. If that’s right and it’s developed, could the behavior be extended to apply to all conditions using much of the same code? Outside Boolean conditions, would this be a massive breaking change? I think so just want to confirm. I’m asking because I think there would be an appreciable performance difference between the two for CEP. I think Drools made changes along these lines for that reason

mikerod18:01:05

@alex-dixon I think the re-ordering (or not) is still being discussed in the 373 linked above. There already is re-ordering happening. It sounds like there may be some lean towards not needing to do that anymore. You should check out some of the comments in that issue now. I did mention the lazier evaluation thing there, but there are still concerns I’d have with that overall.

mikerod18:01:43

And yes, that paper is good. I first heard of it from Ryan putting a reference to it in the Clara GitHub repo @ https://github.com/cerner/clara-rules/wiki/Introduction#the-rules-engine

sparkofreason18:01:34

If I were to call insert! from within an async callback for an effect triggered on the rhs of a rule, I assume that the context would be goofy and result in an exception or other undesirable behavior. Is there a best practice for capturing that context? The use case would be leveraging truth maintenance for facts inserted async, e.g. results from an http request.

mikerod19:01:17

@dave.dixon I’d expect the async response to be do an external insert when it is done

mikerod19:01:33

You’d “capture context” just via the variable bindings you passed to the async call

mikerod19:01:04

Oh, woops, missed part of your purpose

mikerod19:01:44

I think you’d have to model the fact that you caused the effect externally as a fact for TMS to help you. Example:

mikerod19:01:44

I don’t really like the maybe-undo-async-thing part of that. It doesn’t know which DownstreamResult may now be invalid and offloads it all to the external fn ext-maybe-undo-async-thing

mikerod19:01:56

I think there may be a better way around that

mikerod19:01:01

I made it so original-rule is always satisfied via the accumulator

mikerod19:01:15

So you can carry that information forward on which path you should take

sparkofreason19:01:17

Yes, that's how I'm doing it now. Like you say, it's fine when all the relationships are clean, but otherwise gets messy.

sparkofreason19:01:35

Referring to the first example.

mikerod19:01:07

So in my 2nd example, you can actually filter DownstreamResult if you track which bs they originally were associated with via that information being conveyed externally and back on the inserted new facts

mikerod19:01:32

It isn’t perfect, you still have to make an association on the facts, however, I think it could be practical

mikerod19:01:56

This is regarding one part of the overall problem

mikerod19:01:20

You also have the problem of when the async request is finished, ensuring it inserts to the session that it came from in its final state

mikerod19:01:43

so after the fire-rules that triggered the async request has completed

mikerod19:01:51

In a single-thread, I think that is not an issue

mikerod19:01:05

And you may be doing this single-threadedly

mikerod19:01:44

The async call though would need to have a way to access the session when it is finished

sparkofreason19:01:23

I have a way of handling session. But what I really want is to be able to do the final insert such that the fact is a logical consequence of the rule lhs. Not sure if that actually is meaningful given how rete works.

alex-dixon19:01:11

I’m not sure whether using Clara’s truth maintenance directly allows that, but you should be able to simulate it using unconditional inserts/retracts, other rules, and facts that represent the async event cycle. A poor attempt:

(defrule make-request-when
  [?task <- AsyncTask]
  =>
  (retract! ?task)
  (insert-unconditional (->AsyncRequest ?task))
 (async-side-effect! my-session ?task)

(defn async-side-effect! [session fact] (request! fact (fn [err res] 
(if err (insert session (->AsyncTaskError err fact)
(insert session (->AsyncTaskSuccess res fact))

(defrule on-async-task-success
  [?success <- AsyncTaskSuccess ?res ?fact]
  [?request <- AsyncTaskRequest ?fact]
=>
(retract! ?success ?request)
(insert-unconditional! (->SomeFactRepresentingResponseFromThisKindOfRequest ?res)
 
  ;; similarly with error

sparkofreason19:01:43

I have something similar, and it works nicely. But it would be nice if I could avoid the manual truth maintenance.

mikerod21:01:23

I don’t think anything built-in would allow you to reliable have an actual “handle” on the mutable session state during fire rules for an insert! to go off later yet, still correctly be tracked with TMS

mikerod21:01:35

there’d be quite a bit of complications for the engine to try to support that even I think

mikerod21:01:50

Not to mention the fire-rules wouldn’t be able to be “done” until all async actions were done

mikerod21:01:13

and it’d have concurrency issues in a multi-threaded environment

sparkofreason21:01:45

Agreed. Maybe the right(ish) answer is to model facts as something like a promise. The semantics and behavior would have to be constrained, so it isn't just mutating facts behind your back without properly updating the session. But the basic concept seems like a way forward, because conditionally inserting a promise as a fact means it and whatever value it returns will get retracted when TMS requires it.

sparkofreason22:01:40

The thing I'm trying to avoid is having to manually perform truth management for facts inserted as the result of async effects. In the big picture, those facts are logical consequents of whatever condition triggered the async effect.

mikerod22:01:39

Yeah,I think the case is interesting

alex-dixon19:01:11

I’m not sure whether using Clara’s truth maintenance directly allows that, but you should be able to simulate it using unconditional inserts/retracts, other rules, and facts that represent the async event cycle. A poor attempt:

(defrule make-request-when
  [?task <- AsyncTask]
  =>
  (retract! ?task)
  (insert-unconditional (->AsyncRequest ?task))
 (async-side-effect! my-session ?task)

(defn async-side-effect! [session fact] (request! fact (fn [err res] 
(if err (insert session (->AsyncTaskError err fact)
(insert session (->AsyncTaskSuccess res fact))

(defrule on-async-task-success
  [?success <- AsyncTaskSuccess ?res ?fact]
  [?request <- AsyncTaskRequest ?fact]
=>
(retract! ?success ?request)
(insert-unconditional! (->SomeFactRepresentingResponseFromThisKindOfRequest ?res)
 
  ;; similarly with error