Probably not relevant and more of an FYI, but if the condition?
is simply equality it could be done with a third argument to =
.
(r/defrule some-rule
[Request (= ?resource resource "GET")]
=>
(println ?resource))
@souenzzo wait, really? Is there a list of functions that Clara handles specially?
I mean, knows how to join, other than =?
[Request (= resource "GET")]
=>
(prn "GET")
Onde it will only match if resource
is GET
đ
you can also do
[?request <- Request (= resource "GET")]
=>
(prn ?request)
Will print the "full record"I use =
and contanis?
. I learned it when I did not understand how clara works then never search for it.
As a newcomer itâs not super clear which functions are built-in. This is definitely an advanced user library :)
Thanks @ethanc ! This is actually something that I did need (for a different rule)
I'm believe that the only functions that Clara handles specially are the equality expressions: https://github.com/cerner/clara-rules/blob/master/src/main/clojure/clara/rules/compiler.clj#L213-L223
3đYeah, =
is the only special thing
It still means =
too, but it can also be used for unification purposes/binding variables
nothing is special about contains?
(or anything else)
Agreed with other comments that it is just = that is special when used as a top-level value in the constraint to create/join on bindings (starting with ?)
that has perf benefits in that those joins are done by hashing
otherwise you can use arbitrary functions and they should behave the same as elsewhere
While reading the docs, it goes from straightforward to advanced very quickly. In http://www.clara-rules.org/docs/rules/, I fully understand the free-lunch-with-gizmo
because there's no ?
binding, you're matching that an item is :gizmo
, but then in the sophisticated example:
(defrule grant-discount-months
[Purchase (= ?month (get-month date))]
[DiscountMonth (= ?month month)]
=>
(insert! (->GrantDiscount :for-month ?month)))
The =
doesn't have the same meaning (in the Purchase condition) as the straightforward example, but it does in the DiscountMonth condition?it has the same meaning in that it requires equality, but clojure.core/= wonât be called
Not quite.
=
is unification. So, it requires the expression to be true. If there are variables in it that do not yet have a value, the variables are "assigned" such to make it true. If the variables are already assigned, it works like clojure.core/=
Thatâs a reasonable way to think about it
but Clara may optimize on it
when unifying on a ?
binding
it uses it to build the rete graph
> =
is unification
This distinction is makes sense!
makes a hash-based match for nodes known to be doing =
based bindings
but =
is also just =
when equating to constant values etc
If there are many possible values for a variable, it can assign each value consecutively.
you can do [Purchase (= ?month month "JAN")]
for example
(*and what @mikerod is saying is true, I'm only describing the semantics, it doesn't actually work like that.)
1đŻyeah, semantics are most important
just making sure someone may not get carried away and try to print within clojure.core/=
or something and wonder why it isnât always called hah
unlikely
[Purchase (= ?month month "JAN")]
binds the value of the field month
to ?month
, when (= month "JAN")
(via clojure.core/=
)
Of course in this case, ?month
would just be âJANâ
so perhaps something a bit more useful than that đ
This page on the docs might be of interest: http://www.clara-rules.org/docs/hash_joins/
Woah secret docs
â`=` is unificationâ => correct. Note that this is for top-level constraints though, when nested inside a constraint that isnât the case i.e. [A (= ?b c)] vs [A (stuff (= ?b c))]
1âHah not secret, just nested inside the âperformance optimizationâ page
Or more precisely on my last, that is true if youâre trying to create new bindings - itâs still unification semantically if youâre using bindings from before
> [A (= ?b c)] vs [A (stuff (= ?b c))]
Yes! This is what I ran into immediately, I wanted to use my own equality function, but I got pointed to using :test
instead.
BTW thank you all for helping me understand this!
some of the semantics around = can get weird, since it kind of plays 2 roles depending on context
like when how you canât nest it within another call to do a unification
but most of the time not a big deal
@eraserhd Agreed with @mikerodâs previous comments - Another interesting way that this played out (both myself and Mike spent a while doing perf optimizations on Clara) is that in practice, it turned out that even for large cases (hundreds of thousands of facts/tens of thousands of rules) the constant factors seemed to be most important. Hashing turned out to be a large percentage of work performed for example. A lot of these optimizations (on the Clojure side) are in the memory.cljc namespace with lots of Java interop etc. That said, this was in use-cases where we didnât really have lots of data that we were just going to end up discarding, and thereâs definitely cases where more laziness could be useful.
Is it possible to transform the output of defquery
or would I need to do that in a wrapper function? The RHS of a defrule
is just Clojure but that doesn't seem to exist in defquery
s
@jvtrigueros defquery
has no RHS
you can create facts in rules with defrule
that do some transformations so there is less to transform once you get it from the query
but the query return val will just be the maps with the binding keys to the values they are bound to in the query
Thanks! In the query
docs, it suggests one can write a query like so:
(query session get-by-last-name :last-name âJonesâ)
How would one write the defquery
for that?
(defquery get-by-last-name
[:last-name]
[?person <- Person (= last-name :last-name)])
I'm only able to create defquery
s that have ?
:
(defquery get-by-last-name
[:?last-name]
[?person <- Person (= last-name ?last-name)])
But then the query call wouldn't be using :last-name
but :?last-name