[ANN] clara-rules 0.1.0 released -- rules as a control structure

891 views
Skip to first unread message

Ryan Brush

unread,
Sep 23, 2013, 10:16:12 PM9/23/13
to clo...@googlegroups.com
This is the first release of Clara, forward-chaining rules in Clojure. 

Details on the github site:


I've also posted the rationale for what I'm doing here:

http://www.toomuchcode.org/2013/09/rules-as-control-structure.html

The gist is that forward-chaining rules are a great tool for many problems and Clojure's strengths can address some weaknesses in existing production systems. Right now Clara supports most of the major features seen in production systems, embraces Clojure values like immutability, and is powerful enough for a number of use cases. It still needs to be profiled and subjected to more rigorous testing before I'd consider it production ready, but this release is for anyone interested in experimenting with it.

Dmitry Groshev

unread,
Sep 24, 2013, 6:41:01 AM9/24/13
to clo...@googlegroups.com
I'm curious how this relates to core.logic. If I understand correctly, Clara can be compiled to core.logic and utilize it's search, doesn't it?

Ryan Brush

unread,
Sep 24, 2013, 7:42:02 AM9/24/13
to clo...@googlegroups.com
Clara is a forward-chaining production system -- think Jess, Drools or CLIPS (but in pure Clojure, of course.). Core.logic offers constraint-based logic programming, more along the lines of Prolog and obviously with a strong relationship to Kanren.

These approaches are complementary; which one to use really depends on the problem you want to solve. If you can describe a problem as a search space over a set of constraints, core.logic is almost certainly a better fit than Clara.

In contrast, Clara targets the expression of complex and arbitrary domain-specific knowledge. Even a functional approach to programming can become unwieldy if business rules are frequently changing and have arbitrary relationships to other rules. Those functions would need to be deeply chained together, with frequent changes forcing them to be re-wired. Production systems allow the logic to be expressed independently, where authors need not worry about other rules, order of execution, or wiring them together. The engine then runs the rules against a set of input and ensures the working memory reaches a consistent state.

I wrote about this in more depth here: https://github.com/rbrush/clara-rules/wiki/Introduction

Dmitry Groshev

unread,
Sep 24, 2013, 3:02:33 PM9/24/13
to clo...@googlegroups.com
I see your point. By the way, the documentation is outstanding, especially for first release. Great work!

On the other hand, I can't help but think that Rete algorithm looks like a part of logic programming system. I understand that this is a corner case (Prolog does a lot more than just scanning through facts/rules) and therefore can be solved much more efficiently, but is there a way to blend this approaches? I've also found [1] and this supports my suspicion that the distinction is more of a historic/business kind rather than fundamental one.

Your argument on execution order problems is valid, especially for Prolog. But minikanren is not so brittle in this sense. Moreover, "runtime" assertion of facts in regard to core.logic already surfaced a few times in this list [2], so effective addition of facts and rules can be very beneficial for core.logic. On the other hand, if I understand correctly, information on constraints (both real, integer and FD) can be useful for rule-based systems to reduce search space of rules that can be affected by new fact. So combined approach seems useful to me.

Ryan Brush

unread,
Sep 24, 2013, 7:40:59 PM9/24/13
to clo...@googlegroups.com
I appreciate the kind words!

You're right that the lines between forward- and backward-chaining systems are blurry, with some systems incorporating ideas from both. Perhaps more important than that is how easily we can express the logic for a given problem. While it's possible to write, say, a Sudoku solver in Clara, it really isn't the right tool for that sort of constraint-based logic. Conversely, some forward-chaining rules may not be as easily expressed in a system that emphasizes constraints. Some examples I put together to demonstrate Clara are at [1]; I hope these are fairly clear. I'm not so sure this type of arbitrary, changing business logic is as easy to modularize and express in other systems.

To be clear, I think core.logic is awesome, and am uncomfortable drawing any comparison between it and Clara. I also can imagine leveraging core.logic and its ideas in Clara itself as this evolves. As a starting point, however, Clara is targeting a different class of problem.  If working with a problem that could benefit from rules, I'd suggest thinking of the simplest way that problem can be expressed, and choosing a technology that most closely aligns with that.

I hope this makes sense! I wish I had some clear litmus test to contrast these systems, but I'm still learning myself. ;)

Mark Engelberg

unread,
Sep 24, 2013, 8:00:35 PM9/24/13
to clojure
I used CLIPS (another forward-chaining rule system) for several years, and the way I tend to explain it to people is that it is the best tool for the job when your code would look like an enormous cond with thousands of cases, executed over and over, because:

1.  The Rete algorithm can "jump to the right branch" more efficiently than testing each case one by one in some linear order.
2.  When you have thousands of cases, it can be difficult to ensure that they are in exactly the right order and/or don't overlap.  Forward-chaining systems let you express the cases more declaratively and apply precedence rules judiciously rather than thinking about precedence all the time.

I think a forward-chaining system would also make a great foundation for a project that requires some sort of dataflow architecture.

I agree with Ryan that it tends to be useful in different contexts than constraint solvers.

Angel Java Lopez

unread,
Sep 24, 2013, 9:16:26 PM9/24/13
to clo...@googlegroups.com
+1


--
--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clo...@googlegroups.com
Note that posts from new members are moderated - please be patient with your first post.
To unsubscribe from this group, send email to
clojure+u...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
---
You received this message because you are subscribed to the Google Groups "Clojure" group.
To unsubscribe from this group and stop receiving emails from it, send an email to clojure+u...@googlegroups.com.
For more options, visit https://groups.google.com/groups/opt_out.

Alan Moore

unread,
Sep 25, 2013, 11:03:16 PM9/25/13
to clo...@googlegroups.com
+.010

Thanks for the update! I'm still working on mods for ClojureScript... I'll send a pull request when I'm done.

Alan

Ryan Brush

unread,
Sep 25, 2013, 11:25:27 PM9/25/13
to clo...@googlegroups.com
Sounds great, Alan! I hope the significant refactoring of the rule shredding and optimization I made last weekend didn't disrupt you too much. 

The good news is I think the APIs structure of the code should be reasonably stable now. I'm planning on attacking the accumulator logic next -- it's kind of a mess, has some confusing semantics when facts are retracted, and is pretty inefficient -- but that change should be pretty localized. 

I'm really curious to see how involved a ClojureScript port of this will be. The vast majority of it should be portable, but there are some things JVM-specific. These are somewhat unusual in most Clojure programs, such as inspecting a Clojure record or JavaBean to enumerate the pre-defined fields, making them visible on the left-hand side of the rule. Clara also makes more use of macros than I would expect from most code, necessitated by the fact that it essentially defines a new control structure for logic. But if we can solve those cleanly, I *think* it will translate to ClojureScript pretty well.

On a related note, I recently learned of a JavaScript-based Rete implementation called Nools. [1] We might be able to learn a thing or two from that; I certainly learned a lot from JVM-based rule engines before starting Clara.

In any case, I look forward to seeing what you're up to. I do want to get Clojurescript working with this once I get the JVM-based version a bit more solid and validate it against some problems I'm working on.

[1]

zcaudate

unread,
Sep 26, 2013, 12:45:36 AM9/26/13
to clo...@googlegroups.com
Hi Ryan!

Great work. Can normal clojure maps can be used instead of records?

Ryan Brush

unread,
Sep 26, 2013, 10:23:41 AM9/26/13
to clo...@googlegroups.com
Not yet, although I would like to make use of simple maps natural. I had been toying with the idea of typing into the :type metadata that could be attached to a map, allowing expressions like:

(defrule test-rule 
   [:example/person-map-type (= "Alice" (:first-name this))]
   =>
   (println "Hello, Alice!"))

That way any map with that type annotation could be used in the rule. Today Clara does automatically bind "this" as a reference to the matched object, so functions can be called against it. (I'm not particularly thrilled by the implicit binding of "this", but it is common in rules engines so I included it here.)

The advantage of records is they have a pre-defined type and pre-defined fields, so they are a natural alternative to facts and slots seen in other production systems. But since simple maps are so common in Clojure code I do want to incorporate them here, either by tapping into the type metadata as seen in the above example, or by doing something akin to how multimethods work, where the fact "type" is effectively defined by a function.

I'd love to hear suggestions on this one. The goal is to get the advantages of a production system in a way that feels natural to Clojure developers. What would feel most natural to members of this group?

On Wednesday, September 25, 2013, zcaudate wrote:
Hi Ryan!

Great work. Can normal clojure maps can be used instead of records?

--
--
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clo...@googlegroups.com
Note that posts from new members are moderated - please be patient with your first post.
To unsubscribe from this group, send email to
clojure+u...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
---
You received this message because you are subscribed to a topic in the Google Groups "Clojure" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/clojure/pfeFyZkoRdU/unsubscribe.
To unsubscribe from this group and all its topics, send an email to clojure+u...@googlegroups.com.

Chris Zheng

unread,
Sep 26, 2013, 6:03:24 PM9/26/13
to clo...@googlegroups.com
Hi Ryan!

Thanks for your response. I would love to see maps and nested maps as part of the rules. I find that clara provides great syntax for defining inputs and outputs and I would love to use it as a rules engine just beneath my front end. 

However, most of my work is web based, data is javascript and so I'm converting it into clojure maps and dispatching based on routes

I'm not sure adding a :type field would be a good idea. I've implemented something much simpler to work with arrays of elements with different ways that elements can be selected and its better to work directly with the data itself rather than tag….

I'm really hoping that something similar could be implemented in with routes and data… something like:

(defmaprule notify-client-rep
  "Find the client represntative and send a notification of a support request."
   [:support/request [req] (== ?client (:client req))
   [:add/client/representive [req]  ((req :clients) ?client) (== ?name (:name req))]
=> (println "Notify" ?name "that" ?client "has a support request")
)

Ryan Brush

unread,
Sep 26, 2013, 10:45:58 PM9/26/13
to clo...@googlegroups.com
Hey, I appreciate the thoughts. Funny how posting a project yields use cases you've never thought of. I went ahead and logged an issue to track arbitrary maps as facts here:

https://github.com/rbrush/clara-rules/issues/6

I'm looking for ways to align with you needs, but I don't see an immediately obvious way to do so. Out of respect for this mailing list, it probably seems best to use the github issue to go deeper on this one. 

-Ryan

For more options, visit this group at
http://groups.google.com/group/clojure?hl=en
---
You received this message because you are subscribed to a topic in the Google Groups "Clojure" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/clojure/pfeFyZkoRdU/unsubscribe.
To unsubscribe from this group and all its topics, send an email to clojure+unsubscribe@googlegroups.com.

For more options, visit https://groups.google.com/groups/opt_out.

Chris Zheng

unread,
Sep 27, 2013, 3:10:40 AM9/27/13
to clo...@googlegroups.com
thanks for your thoughts!

zcaudate

unread,
Sep 27, 2013, 5:54:33 PM9/27/13
to clo...@googlegroups.com
I just thought of another feature that I want - persistence... Like saving the rules into some file and loading them back again.
Reply all
Reply to author
Forward
0 new messages