This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
2020-01-21
Channels
- # announcements (24)
- # aws (2)
- # babashka (20)
- # beginners (147)
- # cider (20)
- # clara (43)
- # clj-kondo (3)
- # cljdoc (15)
- # cljsjs (1)
- # cljsrn (36)
- # clojars (19)
- # clojure (64)
- # clojure-europe (4)
- # clojure-italy (45)
- # clojure-nl (1)
- # clojure-spec (20)
- # clojure-uk (26)
- # clojurescript (16)
- # cursive (9)
- # datomic (18)
- # dirac (14)
- # docker (3)
- # fulcro (48)
- # keechma (1)
- # leiningen (32)
- # luminus (1)
- # off-topic (40)
- # pedestal (1)
- # quil (1)
- # re-frame (24)
- # reagent (3)
- # reitit (3)
- # remote-jobs (2)
- # ring-swagger (4)
- # shadow-cljs (115)
- # spacemacs (22)
- # specter (4)
- # tools-deps (76)
Are there any examples out there that show how to define a session in the namespace project.a
, define facts in namespace project.b
, rules in project.c
, and how to import b
and c
into a
to fire rules on them? I'm struggling because I"m sure I don't have namespace usage well...
My two files which fails (I"m looking only at importing rules for this examples, not yet facts):
The session namespace...
The rule namespace I want to import from...
The error I get:
@matthew.pettis I believe you would want to import the fact into the namespace where the rule is using it:
(ns clara-lein.ex06rulesns
(:require [clara.rules :refer :all]
[clara-lein.ex06 :as ex06])
(:import [clara-lein.ex06 Myfact]))
;; Rules namespace for rules for ex06.
;; Define rules
(defrule rule-1
"Rule-1 in rulesns"
[Myfact (= ?size size)]
[:test (> 1 ?size)]
=>
(insert! (ex06/->Rulefail "rule-1" ?size)))
Though this might lead to issues with cyclical dependencies, with the session ns and rules ns.
It might be practical to pull the fact definitions out into a separate ns so that they can be pulled by both ns without the possibility of a cycle.Thank you! If I copy and pasted this correctly, when i run (require 'clara-lein.ex06rulesns)
in clara-lein.ex06
, I get an error that No namespace: clara-lein.ex06rulesns found
. I'll keep poking, but that's my current error...
... and that's when I run the final let
that creates the session...
oops, I take that back. When I run that require statement, I get a ClassNotFound exception for clara-lein.ex06.Myfact.
So, I was able to make this work if I included all of the defrecords, rules, queries, and facts in a different namespace, referred that namespace, and then made a session with mk-session 'source.namespace)
. However, I am struggling to modularize this, so that I can make a session where facts come from one namespace, rules from another namespace, and queries from yet another namespace. I'm not sure if it is the namespace inclusion-ing that I am messing up, or that I don't know the proper syntax on mk-session
or insert
to build up a session that has facts, rules, and queries from these sources in it. An pointing to examples of rules that has that would be appreciated. I am doing this as an exercise to show that you can make a modular rules system and that clara-rules can support that modularity. Which is why I'm making a toy example that is doing this... thanks in advance...
@matthew.pettis there are no special evaluation rules being done by Clara. You have to appropriately require all ns’s you depend on in the order they depend on each other via standard clj :require
If you show your example I maybe can help. I’m confused what you are using to get into a situation you are describing at this point.
@mikerod Thanks for the help! I pushed a repo here of example code that doesn't quite work, but has the rules, facts, and queries in separate namespaces. The part is at the end of the core.clj file, where I assemble a session out of the facts, rules, and queries, to be able to query the session. https://github.com/mpettis/clara-ns-ex
First just style Notes:
In clara-ns-ex.core
, typically all :require
are in one spec, but I guess what you have can work? I haven’t actually tested in recent clj:
(ns clara-ns-ex.core
(:require [clara.rules :refer :all]
[clara-ns-ex.facts :refer :all]
[clara-ns-ex.rules :refer :all]
[clara-ns-ex.queries :refer :all]))
Instead of
fact-sess (apply insert query-sess facts)
use insert-all
fact-sess (insert-all query-sess facts)
just since there is API to make you not need to use apply
with varargs.Second (most important):
You don’t insert
rules and queries. These are needed upfront at mk-session
time. Clara actually does not support dynamically adding or removing rules/queries at all right now. It may be a future potential to add, but there are perf benefits to not doing so. Even if it did allow that later though, you wouldn’t “insert rules”.
insert
is meant for facts, not rules.
what you’d need to do for your example is:
init-sess (mk-session 'clara-ns-ex.core 'clara-ns-ex.rules 'clara-ns-ex.queries)
if you just wanted to automatically include all rules/queries defined in those namespaces.OK, this is super-helpful, thank you so much! I will try these changes as soon as possible.
I was not aware that rules and queries could not be dynamically added. It is nice to see an example of mk-session
with multiple namepaces put in there. I wasn't sure if it was as a varargs or as a vector of namespaces, etc.
@matthew.pettis there is likely an issue or 2 in the github repo discussing dynamic rules. However, you may not need it as much as immediately it seems.
I agree; I don't need dynamic rules. I more needed a hint as to the fact that they are supplied and loaded upon mk-session
.
To that end, I tried your advice, I think I did it faithfully, and wasn't able to make it work yet. My adjustments are at this commit: https://github.com/mpettis/clara-ns-ex/tree/0bdb72e98a8ef657de08579af6ee993c9008a738
When I run that, I still get that Myfact
class cannot be found. I think I'm probably missing something about using defrecord
definitions from other namespaces.
Also, for a baseline, this is how I make it work when everything is in the same namespace... https://github.com/mpettis/clara-ns-ex/blob/nonamespace/src/clara_ns_ex/core.clj
@matthew.pettis so you’re issue isn’t just referring to record symbols. Have to follow normal clojure symbol resolution rules.
Then you typically would use :import in clj (not cljs) to refer to the record class name as the shortened version
Thanks. I thought about that a bit more after I posted, I'll think a bit more carefully about resolution rules, and think I may get it... Thanks for the help; learning Clojure as I learn Clara here...
I really appreciate the help.
fyi, i think i'm closer, but I can't decipher the location of where the error of can't find Class for Myfact, as it won't tell me at what line it is failing. This is the state that I have it: https://github.com/mpettis/clara-ns-ex/tree/f3d6f67346eacb61294205f6da0e1f3073e7428a
I have the import statements, I tested that it worked. I referenced these pages that went with the hint that @mikerod gave me on using import: https://danielcompton.net/2016/05/04/requiring-records-clojure-clojurescript and https://stackoverflow.com/a/23420084/1022967
OK, I got it to work by playing with what did and did not need namespace qualified names, and where. I don't fully understand the rules of when I should and should not yet, but I have a working example to go off of, so thanks for all of your help! Here is the commit that has a working example: https://github.com/mpettis/clara-ns-ex/tree/d077c141d305ef217043bcf44a328c6921311847
Looks like you've got it figured out mostly. :). You don't need the fact class imports in your core namespace, but rather just in the rule/query namespaces that use them. Clara rule and query defs use the same evaluation semantics as normal Clojure code, that is something used, be it a function, class, etc. needs to be resolvable in the namespace where the rule/query is being defined. Also it's somewhat a matter of personal preference, but I find it more clear where things are coming from when I use :as aliases rather than :refer :all, that might help reduce confusion.
Admittedly there's a fair amount of code in Clara dealing with that evaluation, but the end result is to have the same user-facing semantics.
Awesome! I'll take out the require and import statements in core and use :as aliases in the rest and push a cleaner example. Thanks for the help.
I also advocate for :as aliases too. It helps to make it clear where symbols are coming from. ClojureScript doesn’t even have :refer :all support! Hah
I just discovered 'how to ns' by Sierra, reading that to guide me on that: https://stuartsierra.com/2016/clojure-how-to-ns.html
I thought it had some good points. I can’t remember if I fully agreed with it, but analyzing require forms can become a debate of “taste” at a certain point. Hah. He does at least mention its opinionated. 😎
OK, just for completeness and posterity... For this question, which was how to use namespaced rules, queries, and facts in making a session, I cleaned up the namespace declaration, using Sierra's "how to ns" style recommendations, and removed most :require :refer :all statements to be more precise (except for clara-rules
). Here is the commit that is cleaned up per this comment: https://github.com/mpettis/clara-ns-ex/tree/8b78de1442fd8484341cc68d6ac63b7d78cf85e4