-
Notifications
You must be signed in to change notification settings - Fork 115
Guide
Developer documentation is in progress.
Rules are typically defined with defrule, which has this structure:
A simple rule looks like this:
(defrule free-lunch-with-gizmo
"Anyone who purchases a gizmo gets a free lunch."
[Purchase (= item :gizmo)]
=>
(insert! (->Promotion :free-lunch-with-gizmo :lunch)))
Where Purchase is a Clojure Record or Java JavaBean containing an item field. If there exists a purchase that matches the :gizmo keyword, a new promotion is inserted into working memory, by simply creating a new Promotion record.
The left-hand side of the rule -- everything prior to the "=>" in the above -- uses a constraint expression described in the Constraint Expressions section below.
The right-hand side of the rule -- everything past the "=>" in the above example -- is simply a Clojure S-expression and can invoke arbitrary code, or use insert! to insert new information into the working memory.
Queries are typically defined with defquery, which has the following structure:
A sample query looks like this:
(defquery get-promotions
"Query to find promotions for the purchase."
[]
[?promotion <- Promotion])
The first argument is a vector of keywords to indicate parameters to a query. For instance, if we wanted to run a query that retrieves only a certain type of promotions, we might write this:
(defquery get-promotions
"Query to find promotions for the purchase."
[:?type]
[?promotion <- Promotion (== ?type type)]) ; Bind the ?type query to the promotion type.
A caller may then execute that query with arguments. So if we only wanted to find lunch promotions, we might perform the query like this:
(query session get-promotions :?type :lunch)
The conditions used by a query are the same structure as the left-hand side of a rule. See the Condition Expressions section below for usage.
Condition Expressions are the contents of the left-hand side of rules, or the constraints used in queries.
This part of rules and queries contains a series of expressions, each of which is one of the following:
- A fact expression, which selects a fact based on some given criteria.
- A boolean expression, which is simply a hierarchical and/or/not structure of other expressions.
- An accumulator, which is mechanism to reason about collections of facts
- A test, which is an arbitrary Clojure S-expression that can run predicate-style tests on variables bound earlier in the rule or query.
Details on each of these are below.
One ke
Fact expressions are the simplest and most common form of Clara conditions. They start with an optional binding for the fact, in the form of [?variableName <- MyFactType]. The fact type is then followed by zero or more S-expressions which can either be predicates run against a fact, or bindings (via the == macro), as described above.
A simple fact expression may look like this:
[?person <- Person (= first-name "Alice") (== ?last-name last-name)]
This example does the following:
- Matches all facts of type Person
- Eliminates any Person facts that don't have a first-name attribute that is equal to "Alice"
- Creates a new binding ?last-name, which contains the value of the last-name field in matched Person facts.
- Creates a new binding ?person, which contains the value of the matched Person object.
TODO: add details.
TODO: add details
TODO: add details
- Introduction to Clara
- Architecture overview
- clara examples
- Full railroad diagram of Clara syntax
- Clojure API Documentation
- Java API Documentation
Railroad diagrams generated with http://railroad.my28msec.com/rr/ui