Hello, I have question about acc/all
behavior, the following snippet of code:
(ns rules-acc-all
(require [clara.rules :as rules]
[clara.rules.accumulators :as acc]
[clojure.pprint :refer [pprint]]))
(defrecord Customer [id])
(defrecord Reward [id])
(defrecord CustomerReward [id customer-id reward-id])
(rules/defrule quals
[Customer (= ?C id)]
[Reward (= ?R id) (= id "bonus-1")]
;;[?items <- (acc/all) :from [CustomerReward (= id ?I) (= ?C customer-id)]]
[?items <- (acc/all) :from [CustomerReward (= ?C customer-id)]]
=>
(pprint {"?items" ?items}))
(let [session (-> (rules/mk-session 'rules-acc-all)
(rules/insert (->Customer "customer-1")
(->Reward "bonus-1")
(->Reward "offer-1")
(->Reward "offer-2")
(->CustomerReward "cr-1" "customer-1" "offer-1")
(->CustomerReward "cr-2" "customer-1" "offer-2")))
fired (rules/fire-rules session)]
)
Prints
{"?items"
[{:id "cr-1", :customer-id "customer-1", :reward-id "offer-1"}
{:id "cr-2", :customer-id "customer-1", :reward-id "offer-2"}]}
i.e. ?items
contain two elements.
However if condition [?items <- (acc/all) :from [CustomerReward (= ?C customer-id)]]
is replaced with [?items <- (acc/all) :from [CustomerReward (= id ?I) (= ?C customer-id)]]
(pretty much same with unification added for CustomerReward (= id ?I)
the the output would be:
{"?items"
[{:id "cr-1", :customer-id "customer-1", :reward-id "offer-1"}]}
{"?items"
[{:id "cr-2", :customer-id "customer-1", :reward-id "offer-2"}]}
I.e. ?items contain single element, but rule gets triggered twice.
I am trying to wrap my mind around this, but cannot - those two rules set look pretty much same to me
I believe it's because when you specify (= id ?I)
in the accumulator, clara will now make a unique binding for each unique value of id
, so the rule fires once for each id
of CustomerReward
rather than accumulating over all CustomerReward
's with different id
's.
Thanks @dave.dixon - that kind of explains it. I guess my confusion was due thinking that binding (= id ?I)
is kind of "local" to accumulator, in other words it works as sub-select in SQL, however it appears such binding makes ?I
"available" to "outer scope", i.e. I could refer it for unification in clauses which are siblings of accumulator.
Correct. Or you could refer to ?I
in the RHS of the rule, where it would have to be unique.
Yep, then it makes sense