Fork me on GitHub
#clara
<
2018-01-30
>
afurmanov16:01:27

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)]
  )

afurmanov16:01:48

Prints

{"?items"
 [{:id "cr-1", :customer-id "customer-1", :reward-id "offer-1"}
  {:id "cr-2", :customer-id "customer-1", :reward-id "offer-2"}]}

afurmanov16:01:04

i.e. ?items contain two elements.

afurmanov16:01:20

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:

afurmanov16:01:35

{"?items"
 [{:id "cr-1", :customer-id "customer-1", :reward-id "offer-1"}]}
{"?items"
 [{:id "cr-2", :customer-id "customer-1", :reward-id "offer-2"}]}

afurmanov16:01:56

I.e. ?items contain single element, but rule gets triggered twice.

afurmanov16:01:26

I am trying to wrap my mind around this, but cannot - those two rules set look pretty much same to me

sparkofreason17:01:11

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.

afurmanov17:01:24

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.

sparkofreason17:01:14

Correct. Or you could refer to ?I in the RHS of the rule, where it would have to be unique.

afurmanov17:01:37

Yep, then it makes sense