Fork me on GitHub

@wparker @mikerod Thanks so much - that's exactly the examples I was looking for. Assembling rules dynamically will help us handle our mostly similar (but slightly different) rule-sets for different products. Btw destructuring maps also good to know, as records are not often used in our Clojure codebase.


It’s probably good to be aware that if you can order rules in a meaningful order of precedence, Clara will attempt to use that as a heuristic during conflict resolution (picking which rule to fire first, when multiple are eligible).


So if you have rules or sets of rules that naturally depend on other rules/sets of rules, you want to put the dependents after the dependencies. This may not matter to you and may not be worth worrying about until you have a concrete performance concern.


We have relatively low numbers of rules (no more than 100s depending on how granular we make them), but enough for Clara to really help sort out the complexity. 🙂


If I had rules like:

(defrule a [(acc/all) :from [A]] => (insert! (->B)))
(defrule b [(acc/all) :from [B]] => (insert! (->C)))
(defrule c [(acc/all) :from [C]] => (insert! (->D)))
All three rules would be “eligible” to be fired immediately, since the acc/all accumulator is always considered “true”. It will just fire with an empty collection if it has no matches, yet. If I mk-session like
(mk-session [c b a])
This would cause Clara to choose to fire the rules in the opposite order that you would want. The Truth Maintenance System will be sure that your rules logically are correct after firing the rules, however, it will waste cycles firing rules too soon and having to retract and re-fire them later as their dependencies in their LHS change. So you want mk-session like
(mk-session [a b c])


@apbleonard Yeah, it likely isn’t something to concern yourself with now. I’m just brining it to your attention since when you start to consider generating rules, etc, it may be something to consider later on if performance becomes and sort of concern.