Fork me on GitHub
#clara
<
2020-11-02
>
panda00:11:11

hi, i get this issue on compiling a rules namespace. could anyone help me understand what’s wrong with my bindings?

Malformed variable binding for #{?contract-provider ?claim-provider}. No associated value.
(defrule associated-contracts
  [:contract (= ?contract this)]
  [:contract (= ?contract-provider (:subject ?contract))]
  [:claim (= ?claim this)]
  [:claim (= ?claim-provider (-> ?claim
                                  :billing-provider
                                  :identifier
                                  :value))]
  [:associated? (= ?claim-provider ?contract-provider)]
  =>
  (insert! {:resource-type :associated-contract
            :claim ?claim
            :contract ?contract}))

panda00:11:28

i’m using fact-type functions instead of clojure records but i’m having trouble figuring out what are the right patterns

panda00:11:43

in this case i want to bind the entire object to either ?claim or ?contract

panda00:11:04

and i also want to bind nested variables in that map

ethanc00:11:00

I don't have repl open currently, but it looks like this might be because of the multiple conditions with similar fact types. rather than 2 conditions to bind contract and claim, i would assume that you might actually want a single condition for each. Something like:

(defrule associated-contracts
  [:contract 
(= ?contract this)
(= ?contract-provider (:subject this))]
  [:claim 
 (= ?claim this)
(= ?claim-provider (-> this
                                  :billing-provider
                                  :identifier
                                  :value))]
  [:associated? (= ?claim-provider ?contract-provider)]
  =>
  (insert! {:resource-type :associated-contract
            :claim ?claim
            :contract ?contract}))

panda00:11:08

oh i see — that’s definitely a lot cleaner 🙂 it’s still giving me that error though

ethanc00:11:01

hmmm, seems clara is incorrectly moving the joined conditional up in front of the binding itself. Specifially,

[:associated? (= ?claim-provider ?contract-provider)]

ethanc00:11:54

however this condition seems odd to me, you are looking to a fact in the session but not asserting anything based on this fact

ethanc00:11:55

it almost seems as if that should be a test node:

[:test (= ?claim-provider ?contract-provider)]

ethanc00:11:35

or potentially rolled up into the :claim condition itself

ethanc00:11:45

something like:

(r/defrule associated-contracts
  [:contract
   (= ?contract this)
   (= ?contract-provider (:subject this))]
  [:claim
   (= ?claim this)
   (= (-> this
          :billing-provider
          :identifier
          :value)
      ?contract-provider)]
  =>
  (r/insert! {:resource-type :associated-contract
              :claim ?claim
              :contract ?contract}))

panda00:11:04

oh that’s totally it — i’m trying to set it up to have the simple predicate comparing facts and i didn’t realize that you had to name it :test in order for that to work…

panda00:11:44

would the above example give you ones that matched or all combinations of facts?

panda00:11:57

also how does querying for the fact-type-fn work? i tried the following:

(defquery get-associated-contracts
  []
  [?associated-contract <- :associated-contract])

ethanc00:11:11

in the example above, the RHS should execute and insert a fact for each combination of a Claim and Contract that share the same provider

panda00:11:55

that’s perfect! thank you so much!!

ethanc00:11:01

Queries should work the same way while using/not using an overridden fact-type-fn. For example:

(defn test-session
  []
  (-> (r/mk-session :fact-type-fn :resource-type)
      (r/insert {:resource-type :contract :subject :Thomas})
      (r/insert {:resource-type :claim :billing-provider {:identifier {:value :Thomas}}})
      (r/fire-rules)
      (r/query get-associated-contracts)))
should net:
({:?associated-contract {:resource-type :associated-contract,
                         :claim {:resource-type :claim, :billing-provider {:identifier {:value :Thomas}}},
                         :contract {:resource-type :contract, :subject :Thomas}}})

panda00:11:27

ooh i see — thank you! that makes sense