clara

http://www.clara-rules.org/
Matthew Pettis 2020-01-21T03:09:14.002600Z

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...

Matthew Pettis 2020-01-21T03:11:06.003500Z

My two files which fails (I"m looking only at importing rules for this examples, not yet facts):

Matthew Pettis 2020-01-21T03:11:40.003600Z

The session namespace...

Matthew Pettis 2020-01-21T03:12:13.003900Z

The rule namespace I want to import from...

Matthew Pettis 2020-01-21T03:21:27.004500Z

The error I get:

ethanc 2020-01-21T03:29:41.009500Z

@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.

Matthew Pettis 2020-01-21T03:35:19.011700Z

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...

Matthew Pettis 2020-01-21T03:35:41.012100Z

... and that's when I run the final let that creates the session...

Matthew Pettis 2020-01-21T03:37:21.013100Z

oops, I take that back. When I run that require statement, I get a ClassNotFound exception for clara-lein.ex06.Myfact.

Matthew Pettis 2020-01-21T16:20:24.017800Z

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...

2020-01-21T16:59:48.019200Z

@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

2020-01-21T17:00:02.019600Z

You can have things in as many ns’s as you want.

2020-01-21T17:00:27.020500Z

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.

Matthew Pettis 2020-01-21T17:26:01.022100Z

@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

2020-01-22T09:41:27.031Z

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.

👍 1
2020-01-22T09:43:31.031200Z

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.

Matthew Pettis 2020-01-22T12:54:24.031400Z

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.

2020-01-22T13:48:22.033600Z

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

Matthew Pettis 2020-01-22T14:06:02.034100Z

I just discovered 'how to ns' by Sierra, reading that to guide me on that: https://stuartsierra.com/2016/clojure-how-to-ns.html

Matthew Pettis 2020-01-22T14:32:53.037700Z

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

2020-01-21T19:42:12.022300Z

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.

2020-01-21T19:43:09.022500Z

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.

2020-01-21T19:43:59.022700Z

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.

Matthew Pettis 2020-01-21T21:00:57.022900Z

OK, this is super-helpful, thank you so much! I will try these changes as soon as possible.

Matthew Pettis 2020-01-21T21:04:39.023100Z

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.

2020-01-21T21:16:09.023300Z

@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.

2020-01-21T21:16:22.023500Z

Often there are solutions that don’t need that sort of feature at least.