When I touched clara-rules lightly and slept overnight, I wanted to know more about what clara-rules could do, so I made up a miscellaneous problem myself.
Determine if you can buy an item with your money (My Money).
--The final price of the item is calculated in the following steps
# {: fish: pants}
--Item has a category attribute, which changes the tax ratefood 0.1
:cloth 0.2
:alcohol 0.3})```
--After discount, if the taxed price is less than your money, you can buy it
## code
```clj
(require '[clara.rules :refer [defrule fire-rules insert insert! mk-session]])
(def discounted-items #{:fish :pants})
(def tax-rates {:food 0.1 :cloth 0.2 :alcohol 0.3})
(defrecord MyMoney [amt])
(defrecord Tax [category rate])
(defrecord Item [id price category])
(defrecord DiscountedItem [discounted-price category])
(defrecord TaxedItem [final-price])
(defrule DiscountItem
[Item (= ?id id) (= ?category category) (= ?price price)]
=>
(println "Item is" ?id)
(println "Original Price is" ?price)
(println "Discounted item?" (some? (discounted-items ?id)))
(insert! (->DiscountedItem (* ?price 0.9) ?category)))
(defrule TaxItem
[DiscountedItem (= ?category category) (= ?discounted-price discounted-price)]
=>
(println "Tax rate is " (?category tax-rates))
(insert! (->TaxedItem (+ ?discounted-price (* ?discounted-price (?category tax-rates))))))
(defrule EnoughMoney
[MyMoney (= ?amt amt)]
[TaxedItem (= ?final-price final-price) (> ?amt final-price)]
=>
(println "Final price:" ?final-price)
(println "You have enough money!"))
(defrule NotEnoughMoney
[MyMoney (= ?amt amt)]
[TaxedItem (= ?final-price final-price) (not (> ?amt final-price))]
=>
(println "Final price:" ?final-price)
(println "You do not have enough money!"))
--insert! is used in defrule to implicitly add facts to the current session --insert takes an explicitly targeted session as an argument
For example, in the following example on the left side of the DiscountItem rule,
--Item id field? Id --Item category field? category --Item price field? price
I'm bound to.
[Item (= ?id id) (= ?category category) (= ?price price)]
--Variables start with ?
(-> (mk-session)
(insert (->MyMoney 199) (->Item :fish 200 :food))
(fire-rules))
;;Item is :fish
;;Original Price is 200
;;Discounted item? true
;;Discounted Price 180.0
;;Tax rate is 0.1
;;Final price: 198.0
;;You have enough money!
(-> (mk-session)
(insert (->MyMoney 197) (->Item :fish 200 :food))
(fire-rules))
;; Item is :fish
;; Original Price is 200
;; Discounted item? true
;; Discounted Price 180.0
;; Tax rate is 0.1
;; Final price: 198.0
;; You do not have enough money!
(-> (mk-session)
(insert (->MyMoney 215) (->Item :pants 200 :cloth))
(fire-rules))
;; Item is :pants
;; Original Price is 200
;; Discounted item? true
;; Discounted Price 180.0
;; Tax rate is 0.2
;; Final price: 216.0
;; You do not have enough money!
(-> (mk-session)
(insert (->MyMoney 217) (->Item :pants 200 :cloth))
(fire-rules))
;; Item is :pants
;; Original Price is 200
;; Discounted item? true
;; Discounted Price 180.0
;; Tax rate is 0.2
;; Final price: 216.0
;; You have enough money!
(-> (mk-session)
(insert (->MyMoney 521) (->Item :beer 400 :alcohol))
(fire-rules))
;; Item is :beer
;; Original Price is 400
;; Discounted item? false
;; Discounted Price 400
;; Tax rate is 0.3
;; Final price: 520.0
;; You have enough money!
(-> (mk-session)
(insert (->MyMoney 519) (->Item :beer 400 :alcohol))
(fire-rules))
;; Item is :beer
;; Original Price is 400
;; Discounted item? false
;; Discounted Price 400
;; Tax rate is 0.3
;; Final price: 520.0
;; You do not have enough money!
;;Forgot to insert MyMoney, what happens?
(-> (mk-session)
(insert (->Item :beer 400 :alcohol))
(fire-rules))
;; Item is :beer
;; Original Price is 400
;; Discounted item? false
;; Discounted Price 400
;; Tax rate is 0.3
--It was interesting that the rule wouldn't fire if the fact required by the rule wasn't inserted. ――The rules of EnoughMoney and NotEnoughMoney written in the code are redundant, so I feel like an anti-pattern. ――I can't see how to handle when there are multiple Items, so I'd like to attack that area next time. ――I want to explore the possibility of side effects other than printing --I want to find out how retract works
Recommended Posts