This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2017-10-05
Channels
- # aws (1)
- # beginners (57)
- # boot (3)
- # cider (6)
- # clara (49)
- # cljs-dev (47)
- # cljsjs (23)
- # clojure (144)
- # clojure-dev (2)
- # clojure-finland (1)
- # clojure-germany (1)
- # clojure-sg (1)
- # clojure-spec (25)
- # clojure-uk (245)
- # clojurescript (39)
- # core-async (3)
- # cursive (6)
- # datomic (117)
- # emacs (3)
- # fulcro (6)
- # hoplon (10)
- # jobs (7)
- # juxt (5)
- # leiningen (11)
- # om (27)
- # pedestal (4)
- # perun (2)
- # re-frame (22)
- # reagent (35)
- # ring-swagger (11)
- # shadow-cljs (333)
- # spacemacs (10)
- # specter (10)
- # sql (20)
- # vim (8)
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 (RT.java:947)
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:
[:not
[:and
(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?@dg looks like you took care of that with https://github.com/cerner/clara-rules/pull/346 ?
@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.
@mikerod yes, a bit more complex--here’s a more accurate version of that clause, and there are also other clauses in the rule:
[:not
[:and
(x
(= ?foo foo))
(y
((set (map :id ?foo)) foo_id)
(= ?previously_bound_lvar other_id))]]
I ended up working around it by getting all values of x.foo
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
However, https://github.com/cerner/clara-rules/pull/342 could also be related to that sort of logic. There was some edge cases to how it was handled.
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.
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.
Production:
{:lhs [[:not [:and {:type :x, :constraints [(= ?z (:z this))]}]]], :params #{}}
Unbound variables: #{?z} clojure.core/ex-info (core.clj:4593)
@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:
(mk-session
[(dsl/parse-query []
[[:not [:x (= ?z (:z this))]]])])
fails due to Unbound variables: #{?z}
yet this is ok:
(mk-session
[(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.
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
(:require
[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)
(insert
(->Rectangle [1 1] 2 3)
(->Square [3 3] 5))
(fire-rules)
(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
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)
<etc>
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?
Some could be as simple as counter, others are pairs [invites, money], other type of progress possible
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.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)
(insert
(->SpecialIProgress 2 1 "2 out of 3"))
(fire-rules)
(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"
This: https://clojuredocs.org/clojure.core/definterface#example-5568aadfe4b03e2132e7d175 is saying that "Using an interface, only the dot form of the method is available with defrecord"