Fork me on GitHub

Is there any reason why a LHS such as [A (= ?x x)] [B (= ?y y)] where x and y definitely exist (non-nil), would not fire with the order [A ..] [B ..] but would fire with [B ..] [A ..]?


@dadair I don’t see how it should be different. Do you have a more complete rule example?


Just to be sure you don’t have any extra constructs in play?


@dadair @U0LK1552A I wouldn’t expect that kind of ordering to make a difference for non-accumulator rule conditions normally. If you are using manual retractions in rule RHS’s (right-hand-sides) you might be able to get yourself into some odd situations with undefined behavior that could be impacted. A more concrete reproducing example would be helpful to see if there’s a bug. For accumulators, it isn’t the easiest edge case to hit, but is outstanding.


Also, regarding your example

`[A (= ?x x)] [B (= ?y y)]
` I wouldn’t actually expect whether x or y is nil to impact whether the rule fires at least based on those conditions alone


those aren’t result bindings, having a field value of a fact be nil (but the fact itself being nil) is a reasonable possibility and Clara will handle that


Yep, that’s the reason was asking for more details to be sure there aren’t things like accumulators in play. Things get more complicated then.


There seemed to be an issue with using a pre-cached rule session. I was looping through some known mk-session configurations and swapping them into an atom so I could avoid the first performance hit. Then later I'd pull the specific session out of the atom and would insert some facts and fire rules. For some reason this was causing really weird rule activation problems


So for now I've inlined the mk-session and am taking the performance hit until I can figure out what was going on


Could someone please explain the rhs please - I have put a print and an insert! following on from each other on the rhs and the print always happens even if the rule fails?


@mmer The most typical way to structure rules is in a way that they logically express their constraints, but do not necessarily have a guaranteed order the RHS may fire in. insert! inserts facts that are subject to the “truth maintenance system” (aka the TMS) of the rules engine. If a rule fires at some point due to a, potentially transient, match of some facts, but later some of those facts are retracted, the engine will automatically retract the facts that relied on that match being present.


When you do a side-effect like a print, there is no way to “retract” the side effect


There are ways to structure rules that would prevent them from being able to ever fire their RHS “early”. This can be done with setting up the rule to not be able to fire due to some “blocking” or “guarding” criteria in the LHS that you know will not change it’s truthiness later. Also, you can sometimes do some tricks with :salience. However, in many cases, the best idea may be to just avoid the side-effects in the RHS and perhaps do them outside of the rules based on the facts that are found via queries after performing a fire-rules cycle.


There is some documentation on the TMS @


That helps. I thought I was going mad!


@mmer yeah, it can be a tricky detail


The docs say you can nest the boolean operators [:not, :or] etc. I have tried to do something like [:not [:or [] []] without much success. Is this just plain wrong on my part?


@mmer things can get a little tricky with that


So it is good to note that :or is sort of “syntactic sugar” in rules


It can almost be thought of as just splitting the rule into 2 (or more depending on logic in use) rules



(r/defrule with-or
  [A (= ?id id)]
   [B (= ?id id)]
   [C (= ?id id)]]
  (r/insert! (->D)))
Is similar to just writing
(r/defrule side-one
  [A (= ?id id)]
  [B (= ?id id)]
  (r/insert! (->D)))

(r/defrule side-two
  [A (= ?id id)]
  [C (= ?id id)]
  (r/insert! (->D)))


The point in that case is that there isn’t something like “short-circuiting”


and the :or has certain variable visibility issues due to how that works out


When it comes to :not + :or and/or nested :and, it may also be good to note that the engine will convert to DNF (disjunctive normal form)


There may be some variable visibility issues in that transition in certain complex cases


@mmer but if you have an example that demonstrates an issue you are seeing, it’d be probably clearer to just look at that one and explain what is going on


I have eventually just split the rules in two so I do not need the not


sometimes it is clearer to split things up from an comprehension perspective anyways


Probably the most details on this subject can be found in the lengthy old issue comments @


as far as some of the transformations that happen


Only if you were interesting in details though. 😛 Probably not super easy to read through.


To be more precise - when I load up the rules/queries into the session I get :


ExceptionInfo Value does not match schema: {:constraints [(not ("s-expression" ?composition)) (not ("s-expression" a-clojure.lang.Symbol))]} schema.core/validator/fn--1296 (core.clj:155)


@mmer that looks like a syntax error in a rule/query


What sort of thing am I looking for in my rule etc?


It’s hard to decipher without the actual rule DSL that was written (probably could be improved in Clara to try to capture that better) There is probably some missing [ ] if not just having syntax out of order