@souenzzo wait, really? Is there a list of functions that Clara handles specially?
I mean, knows how to join, other than =?
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 :)
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
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.)
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))]
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
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