Search code examples
clojureclara-rule-engine

How to insert a whole fact in Clara without providing attribute values


The following Clara rule code inserts a fact by providing values for all the attributes of the fact type:

(defrule vips-200-promotion
  "This rule creates a special promotion for VIPs that spend +$200"
  [Customer (= true vip) (= ?customerId customerId)]
  [Order (> total 200) (= ?customerId customerId)]
  =>
  (insert! (Promotion. "PROMO-XMAS" ?customerId)));;; Inserts a Promotion fact with promoId = PROMO-XMAS and customerId = value in ?customerId

(defquery get-promos
  []
  [?promotion <- Promotion]).  

But how can a fact, which has previously been bind, be inserted without providing values for its attributes (since you have the whole fact with values in the bind variable)?

Like here:

(defrule vips-promotion
  "This rule creates a special promotion for VIPs"
  [?customer <- Customer (= true vip) (= ?customerId customerId)]

  =>
  (insert! (Customer. ?customer))    ;;; This line fails since insert! is expecting values for all the fact's attribute, but I want to just pass ?customer, which contains the value of the matched Customer.

(defquery get-customers
  []
  [?customerx <- customer])

Solution

  • Minor modification, adding <- to the binding:

    (defrule vips-promotion
      "This rule creates a special promotion for VIPs"
      [?customer <- Customer (= true vip) (= ?customerId customerId)]
    
      =>
      (insert! (Customer. ?customer))
    

    The simple answer here seems that you would have to add a Copy constructor to the Customer class.

    On a side note, a rule like that mentioned above would loop forever as the rhs(Right Hand Side) insert would then trigger the lhs(Left Hand Side) which would then trigger the rhs and repeating forever due to the nature of forward chaining rules engines.