Search code examples
jess

How to combine two rules into one?


I wanted to know how to combine two of my rules, for example:

(defrule Rules::pants
  (declare (auto-focus TRUE))
(answer (ident color) (text red))
  (answer (ident pants) (text yes))
  =>
(printout t "you are wearing red pants"))

(defrule Rules::shirt
  (declare (auto-focus TRUE))
(answer (ident shirt) (text blue))
  (answer (ident red) (text yes))
  =>
(printout t "you are wearing blue shirt"))

If I would write these two rules like:

(defrule Rules::pants
  (declare (auto-focus TRUE))
(answer (ident red) (text yes))
  (answer (ident pants) (text yes))
(answer (ident shirt) (text yes))
  (answer (ident blue) (text yes))
  =>
(printout t "you are wearing blue shirt and red pants"))

I want it to act like an OR statement, to be triggered if any of the conditions is met.


Solution

  • The naive answer would be

    (defrule Rules::pants      
      (or (and (answer (ident red) (text yes))
               (answer (ident pants) (text yes)))
          (and (answer (ident shirt) (text yes))
               (answer (ident blue) (text yes)))
      )
     =>
       (printout t "you are wearing blue shirt or red pants")
    )
    

    The first snag is that this rule fires twice if the the person has red pants and a blue shirt. Most likely, this doesn't matter because the person isn't identified, so we may assume that only one person is on the catwalk.

    Edited The second snag would happen if properties aren't associated with each other, i.e., when a colour and an item can be combined freely. Consider a redneck with blue denim pants and a red checkered shirt. The rule would fire because there is "pants" and "shirts" and "red" and "blue", sufficient to match according to the pattern. But OP has asserted in a comment (see below) that there is some way to avoid this.