There is a requirement to implement a decision table as below:
MemberType Amount => Discount
"Guest" > 2000 => 3%
"Silver" any => 5%
"Silver" > 1000 => 10%
"Gold" any => 15%
"Gold" > 500 => 20%
I would imagine, if properly implemented in Clojure, we can define a rule table as below:
(defrule calc-discount
[member-type amount]
"Guest" (greater-than 2000) => 0.03
"Silver" (anything) => 0.05
"Silver" (greater-than 1000) => 0.1
"Gold" (anything) => 0.15
"Gold" (greater-than 500) => 0.2
)
Of course, there should be a better way in writing/defining such a rule set. Yet the key thing I think is how to define "defrule" to make this happen?
Use core.match! It's a Clojure library for pattern matching.
Your example would turn out a little something like this....
(let [member-type "Gold"
amount 600]
(match [member-type amount]
["Guest" (_ :guard #(> % 2000))] 0.03
["Silver" (_ :guard #(> % 1000))] 0.1
["Silver" _] 0.05
["Gold" (_ :guard #(> % 500))] 0.2
["Gold" _] 0.15
:else 0))
; => 0.2
For this example, you can express the business logic rather concisely with condp
.
(defn discount
[member-type amount]
(condp (fn [[type tier] _] (and (= member-type type) (> amount tier))) nil
["Guest" 2000] 0.03
["Silver" 1000] 0.10
["Silver" 0] 0.05
["Gold" 500] 0.20
["Gold" 0] 0.15
0.00))
(discount "Gold" 600) ;=> 0.2
If you are looking to implement the syntax as in your example, you'll need to write a macro. A very rough example:
(defmacro defrule [name fields & clauses]
(let [exp (fn [f c] (if (list? c) (list* (first c) f (rest c)) (list `= c f)))]
`(defn ~name ~fields
(cond
~@(for [clause (partition-all (+ 2 (count fields)) clauses)
form [(cons `and (map exp fields clause)) (last clause)]]
form)))))
(def any (constantly true))
(defrule calc-discount
[member-type amount]
"Guest" (> 2000) => 0.03
"Silver" (> 1000) => 0.10
"Silver" (any) => 0.05
"Gold" (> 500) => 0.20
"Gold" (any) => 0.15)
(calc-discount "Silver" 1234) ;=> 0.10
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With