Fork me on GitHub

has anyone ever seen an exception from (explain-activations session) when the rules are all working well?

UnsupportedOperationException nth not supported on this type: PersistentArrayMap  clojure.lang.RT.nthFrom (


it seems like explain-activations may just be broken. it expects (:matches explanation) to be a vector of [fact condition] but it's actually a map of {:fact .. :condition ... }


I have a clause like this:

    (x (= ?foo foo))
    (y (= ?foo bar))]]
When it fires, I get this error: > Using variable that is not previously bound…. Note that variables used in negations are not bound for subsequent rules since the negation can never match. To my thinking, the y clause is not a subsequent rule since it’s part of the same :and. I want the clause to match cases where this combination of x and y facts doesn’t exist, though an individual x or y fact may exist. How can I express this?


@enn So Clara (similar to some other rete-based engines) convert the logical structures to DNF (disjunctive normal form). This is typically done to simplify the Rete tree construction and data flow.


So in this case, it’d be NOT (X AND Y) converted to NOT X OR NOT Y and the OR divides the two clauses into distinct chunks. To deal with this, there is typical special handling for “negated conjunctions”.


I wouldn’t expect this behavior since Clara has some special handling of a negated conjunction like this.


Is your rule more complex than just what you posted here?


@mikerod yes, a bit more complex--here’s a more accurate version of that clause, and there are also other clauses in the rule:

     (= ?foo foo))
     ((set (map :id ?foo)) foo_id)
     (= ?previously_bound_lvar other_id))]]


I wonder if the set membership check was messing things up?


I ended up working around it by getting all values of in an accumulator, then doing a :not clause checking those values (if any) against y.foo_id


> I wonder if the set membership check was messing things up? I don’t think it should


So the :not clause is not nested within anything else though right?


I’d have to mess around with that one to see what may be teh issue


However, could also be related to that sort of logic. There was some edge cases to how it was handled.


This isn’t the same as the binding not being present in the rule though


It’s interesting to hear that it should work. I’ll see if I can come up with a minimal test case, and open a ticket if so.


that’d be good to see


 [(dsl/parse-query []
                      [:x (= ?z (:z this))]]]])])


ExceptionInfo Using variable that is not previously bound. This can happen when an expression uses a previously unbound variable, or if a variable is referenced in a nested part of a parent expression, such as (or (= ?my-expression my-field) ...). 
Note that variables used in negations are not bound for subsequent
                                    rules since the negation can never match.
{:lhs [[:not [:and {:type :x, :constraints [(= ?z (:z this))]}]]], :params #{}}
Unbound variables: #{?z}  clojure.core/ex-info (core.clj:4593)


That is pretty minimal


@enn I think the issue is that Clara it not allowing a condition within a negation to introduce a new bound variable


This gets even more minimal:

 [(dsl/parse-query []
                   [[:not [:x (= ?z (:z this))]]])])
fails due to Unbound variables: #{?z} yet this is ok:
 [(dsl/parse-query []
                   [[:y ( = ?z (:z this))]
                    [:not [:x (= ?z (:z this))]]])])


The case of a single condition making a bound variable within a negation doesn’t make sense. However, in negated conjunction like in your previous example it does. I think this may be an edge case that Clara isn’t appropriately handling.


I can log the issue


Thank you!


Hi, I wonder if I have facts like Shape, Rectangle, Square, what would be recommended way to query all shapes?


I am new to Clojure/Clara, and what I am trying to achieve is to make query find-all-shapes to return rectangles as well as squares:

(ns dsl.test
    [clara.rules :refer :all]

(defrecord Shape [center])
(defrecord Rectangle [center width height])
(defrecord Square [center width])

(defquery find-all-shapes
  [?result <- Shape]

(println (-> (mk-session 'dsl.test)
             (->Rectangle [1 1] 2 3)
             (->Square [3 3] 5))
           (query find-all-shapes)))


From clara documentation I guess I have to make Shape an ancestor of Rectangle and Square, but not sure how to do this and wether it is right direction at all.


@alex.furmanov Clara’s defaults are to use the type and ancestors fn’s from Clojure


So you can work it into those in several different ways


I’m not sure if you are using clj or cljs


if you are using clj and like defrecord to define your types you could just make a marker interface and use the standard Java type hierarchy

(definterface Shape)
(defrecord Rectangle [center width height] Shape)


You could also utilize Clojure’s derive


From your example it isn’t completely clear, but I don’t think you actually have facts that are actually the type Shape e.g. (->Shape [1 1]) right?


No, the real case is different: facts are indications of some sort of progress.


Some could be as simple as counter, others are pairs [invites, money], other type of progress possible


Thanks, @mikerod! The (definterface ...) works!


No problem. Technical note: for Clojure I would choose definterface as the way to mark the record hierarchy just because using defprotocol for it’s underlying generated interface is a bit of a gray area. You could get away with defprotocol as well though. It has edge cases though and it may be better to avoid.


If you are still interested, what I mean is, e.g.

(defprotocol Shape)

(extend-type String Shape)
Doesn’t mean that String’s are now considered to be Shape’s by the built-in Clojure type hierarchy. Also, the protocol will leave a var by the name of Shape that will clash with the classname produced in your ns and that is confusing as well.


I did not know that, thanks for explanations!


How to call interface method in LHS constraint?

(definterface IProgress
  (^int counter [])
  (^int customer [])

(defrecord SpecialIProgress [counter_ customer_ details] IProgress
  (counter [this] (+ counter_ 1))
  (customer [this] 1)

(defquery find-all-i-progresses
;;  [?result <- IProgress (= 1 .customer)] ;; DOES NOT WORK
  [?result <- IProgress]

(println (-> (mk-session 'dsl.test)
    (->SpecialIProgress 2 1 "2 out of 3"))
  (query find-all-i-progresses)))


If I uncomment [?result <- IProgress (= 1 .customer)] line I am getting an error: "Unable to resolve symbol: .customer in this context"


Cannot use customer in constraint either, same type of error


This: is saying that "Using an interface, only the dot form of the method is available with defrecord"