Writing Rules

Most users write rules with defrule, which uses this structure:

defrule railroad diagram

Here’s a simple example:

(defrule free-lunch-with-gizmo
  "Anyone who purchases a gizmo gets a free lunch."
  [Purchase (= item :gizmo)]
  =>
  (insert! (->Promotion :free-lunch-with-gizmo :lunch)))

Hopefully this seems pretty intuitive, but let’s take a closer look at the pieces. We start with:

(defrule free-lunch-with-gizmo
  "Anyone who purchases a gizmo gets a free lunch."

These just declare the rule name and include an optional documentation string. Next we have the rule’s left-hand side, which is everything before the => symbol:

  [Purchase (= item :gizmo)]

The left-hand side holds the conditions needed for the rule to fire. In this case we just check if there is a Purchase record (in this case a Clojure record or Java Bean) with an item that is a gizmo.

Now we look at the right-hand side of the rule, everything after the => symbol:

(insert! (->Promotion :free-lunch-with-gizmo :lunch)))

This is just a Clojure expression! It can call arbitrary functions or even have side effects. In this case the expression is insert a new fact into the working memory, that there is a free lunch promotion here.

Here’s one that is a bit more sophisticated:

(defrule grant-discount-months  
  [Purchase (= ?month (get-month date))]
  [DiscountMonth (= ?month month)]
  =>
  (insert! (->GrantDiscount :for-month ?month)))

Here we demonstrate variable binding and unification between rule conditions. This calls some get-month function and binds it to a ?month variable, and the rule will only be satisfied if there is is a discount that matches the month. Details on this are in the Writing Expressions documentation.

What’s next?