clara

http://www.clara-rules.org/
afurmanov 2018-01-30T16:05:27.000629Z

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

afurmanov 2018-01-30T16:05:48.000071Z

Prints

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

afurmanov 2018-01-30T16:06:04.000005Z

i.e. ?items contain two elements.

afurmanov 2018-01-30T16:07:20.000673Z

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:

afurmanov 2018-01-30T16:07:35.000366Z

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

afurmanov 2018-01-30T16:07:56.000768Z

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

afurmanov 2018-01-30T16:09:26.000051Z

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

sparkofreason 2018-01-30T17:01:11.000711Z

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.

👍 2
afurmanov 2018-01-30T17:12:24.000194Z

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.

sparkofreason 2018-01-30T17:13:14.000524Z

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

👍 1
afurmanov 2018-01-30T17:13:37.000611Z

Yep, then it makes sense