oracle-samples/clara-rules

"Unable to resolve symbol" using bound variable in accumulator

Opened this issue · 1 comments

Is it possible to have bound variables inside an accumulator?

(defrule variable-binding-in-accumulator
  [:the-keyword-e (= ?v (:v this))]
  [?xs <- (acc/all ?v) :from [:interesting-fact]]
  =>
  (println "[variable-binding-in-acc] " ?xs))
java.lang.RuntimeException: Unable to resolve symbol: ?v in this context
clojure.lang.Compiler$CompilerException: java.lang.RuntimeException: Unable to resolve symbol: ?v in this context, compiling:([...])
             clojure.lang.ExceptionInfo: Failed compiling accumulator                                         
{:expr (clojure.core/fn [?__env__] (clara.rules.accumulators/all ?v)),
:condition {:type :interesting-fact, :constraints []}, 
:accumulator (clara.rules.accumulators/all ?v), :env nil}

Accumulators currently do not support this sort of parameterization. It isn't immediately clear to me how hard it would be to support it either. I've thought about it in the past, but don't remember.

Accumulators are created during the compilation of the rule network. This means that their construction do not have any "visibility" into runtime working memory state things like variable bindings.

Obviously, you could just do what you are trying here in the RHS, which is the most straightforward.

(defrule variable-binding-in-accumulator
  [:the-keyword-e (= ?v (:v this))]
  [?fs <- (acc/all) :from [:interesting-fact]]
  =>
  (println "[variable-binding-in-acc] " (map ?v ?fs)))

However, if you are trying to build it into the rules a bit more, you could try to break it into two steps where one rule is the "map" and the other rule is the "accumulate".

(defrule map-facts
  [:the-keyword-e (= ?v (:v this))]
  [:interesting-fact (= ?x (?v this))]
  =>
  (with-meta {:mapped-val ?x}
    {:type :mapped-fact}))

(defrule all-mapped
  [?xs <- (acc/all ::mapped-val) :from [:mapped-fact]]
  =>
  (println "[all-mapped] " ?xs))

I don't know how your fact structure looks or how you are doing your type dispatching. I used clj metadata :type here which works with type, the default type-fn in Clara.