Fork me on GitHub
#clara
<
2021-09-24
>
Elias Levy03:09:27

Hello. Apologies if this is obvious, but I am new to Clara Rules. I am observing different behavior depending on whether the RHS uses insert-alll! or insert-all-unconditional!. A rule with a LHS of [A] [:not [B]] and with a RHS that inserts B works as expected if I use insert-all-unconditonal!, but it loops continuously evaluating the rule over and over if I use insert-all!. It is as if the evaluation loop does not find B in the working memory if it has been inserted logically when evaluating [:not [B]]. Is this expected?

ethanc03:09:04

Yes, in clara we have the idea of truth maintenance: http://www.clara-rules.org/docs/truthmaint/ Clara re-evaluates the state of the session, inserting and retracting facts that logically should or shouldn't exist until a steady state exists, ie. no new facts are inserted or retracted. insert-all! abides by truth maintenance, where as insert-all-unconditional! does not. Meaning that a rule that is logically cyclical, and using insert-all! would loop forever, as opposed to stopping evaluation. By logically cyclical, i mean one could probably equate it to paradoxical... A rule as described above would be just that, for example the rule is telling clara: If an A exists without a B produce a B, however in doing so the original statement is no longer valid, thus clara must "rectify"(retract) this logical inconsistency. Making the statement truthful again, causing the fact to be re-inserted... and thus the cycle proceeds ad infinitum. Will Parker spent some time detecting these sorts of loops: https://github.com/cerner/clara-rules/issues/275

Elias Levy04:09:37

Aha! Thank you. I thought I groked truth maintenance, but it did not occur to me that the rule would invalidate itself when performing the logical insert.

mikerod12:09:04

@U02FH7G7MDH I’d add to use caution with unconditional inserts. They are outside of TMS so can cause the rules to become order dependent/sensitive, since they no longer maintain logical validity throughout the firing of the rules and insertions or retractions of facts during the fire-rules loop.

mikerod12:09:57

Usually the solution is to reframe the problem you have in a way that avoids the logical contradiction, ie. not B => B and continue to use the default inserts (not unconditional type) that participate in truth maintenance

mikerod12:09:27

I think that situation often comes up when you are attempting to have “uniqueness” in your inserts - ie. you don’t want to insert B multiple times. A way to work around that, is to insert some intermediary fact type, eg. BCandidate, with no cardinality concerns. Then have an aggregate rule that takes all BCandidates and aggregates it to a single B fact - so you end up with the single cardinality/unique B fact for later rules to reason about. eg.

[?bcs <- (acc/all) :from [BCandidate]]
=>
;; Build B however, is appropriate based on the candidate collection; using `first` here for demo
(r/insert! (-> ?bcs first map->B))

Elias Levy17:09:36

Thanks for the tip. I'll keep that in mind. In this particular case, the unconditional insert seems like the right approach, as the fact inserted is being used to indicate that an action with a side-effect was taken, a side-effect that can't be reversed. Basically the rule is meant to fire the side-effect but only once.

ethanc04:09:38

No problem at all, and welcome to the community 🙂

👍 3