This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2015-11-30
Channels
- # admin-announcements (13)
- # announcements (2)
- # avi (1)
- # aws (10)
- # beginners (427)
- # boot (3)
- # cider (4)
- # clara (26)
- # cljs-dev (21)
- # cljsrn (24)
- # clojure (205)
- # clojure-dev (32)
- # clojure-india (26)
- # clojure-japan (1)
- # clojure-russia (256)
- # clojurescript (41)
- # clojurex (1)
- # cursive (38)
- # datavis (99)
- # datomic (15)
- # emacs (19)
- # events (2)
- # funcool (5)
- # immutant (45)
- # ldnclj (3)
- # om (60)
- # omnext (4)
- # onyx (383)
- # overtone (7)
- # parinfer (1)
- # re-frame (3)
- # reagent (7)
- # ring (1)
- # testing (5)
@ryanbrush: Is it possible to use [:or [?foo <- my/accumulator [X (= a 1)]] [?bar <- my/accumulator [Y (= b 2)]]]
@ryanbrush: here's a sketch of what we imagine:
(defrule thing-a
[?foo <- [:or
[my/accumulator [Foo (= a 1)]]
[:not [Foo (= a 1)]]]]
=>
(when-not (nil? ?foo)
(insert! (map->Bar ?foo))))
We want Foo to be optional, but when it exists, we'd like to accumulate over matching Foo facts.
The best way to solve this problem is to have my/accumulator provide a default value. That way if there are no Foo records, the default value will be returned from the accumulator and propagate down.
For instance, the provided sum accumulator will return a sum of zero if there are no items to sum.
As a side note, you can't quite think of [:or]'s in rules quite like you'd think of or expressions in Clojure. [:or ..] doesn't "return" a value that can be bound to. (In fact, in the Rete algorithm [:or] actually causes two separate rules to be generated for each branch.)
@ryanbrush: thanks!
@devn By the way, when fiddling with this I noticed Clara isn't reporting an error if a user attempts to bind a variable in an unsupported location. This is a bug, so I logged it here https://github.com/rbrush/clara-rules/issues/144
@ryanbrush: that is good to know, indeed
@ryanbrush: trying to be respectful of your time here, but another question: with accumulators, can I make a function which produces an accumulator and use that in the LHS?
@devn Definitely! The accumulators in clara.rules.accumulators are all just functions that return accumulators and should be a good reference. They use constants for the initial value but you can easily pass it as a param.
asking because all of the examples i've seen are def'd and only took the field to compare on
cool, guess I could have tried it, but didn't know calling a function in place of a def'd accumulator had any edges i needed to be aware of
Any function that returns an accumulator will work. The provided ones just happen to use fields.
@ryanbrush: a couple other small bits
- Any reason that things like min/max couldn't optionally take a function to coerce the value of a field to be comparable? For instance, dates.
- Using reduce-to-accum
seems to imply :supports-retract
given that min
, max
etc. call comparison-based
, which in turn calls reduce-to-accum
with an initial value of nil
. Is that true? I remember reading the pull request a couple of times, but are there any good rules of thumb to use when building accumulators to know that you've supported retraction? Now that I write that out, my other question is: When retract
is mentioned, is it talking about automatic retraction, explicit retraction, or both?
As long as your accumulator has a retract-fn, it supports retraction. reduce-to-accum is a convenience function that makes it easier to turn general reduce functions into accumulators by (by default) creating a retract-fn that removes the retracted item from the accumulator and re-runs the reduce. In some cases you can create more efficient retract-fn implementations. See, for instance, sum...to retract a value from a sum you can just subtract the value, which is of course more efficient than re-running the entire sum with the value removed.
Really the retract-fn is just to "undo" the presence of an item in the accumulated value, like subtraction undoes the value in a sum. the reduce-to-accum just offers a "brute force" way to do this for all reduce functions by re-running them. In some very performance-sensitive cases where you don't care about retraction you can skip supporting it, but I wouldn't do so unless you have a special need.
FWIW, Clara accumulators work pretty much exactly like the same concept in Jess and Drools. You just write the functions in Clojure. 😉
@ryanbrush: that's a lovely explanation, thank you!