The world of clara-rules (2)

Last post

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.

problem:

Determine if you can buy an item with your money (My Money).

--The final price of the item is calculated in the following steps

  1. Discount
  2. Taxation --Discount 10% if Item is included in the discount target # {: fish: pants} --Item has a category attribute, which changes the tax rate

food 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!"))

Difference between insert! and insert

--insert! is used in defrule to implicitly add facts to the current session --insert takes an explicitly targeted session as an argument

You can bind variables on the left side of defrule!

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 ?

Miscellaneous test

(-> (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

Impressions

--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

Sequel

Recommended Posts

The world of clara-rules (2)
The world of clara-rules (4)
The world of clara-rules (1)
The world of clara-rules (3)
The world of clara-rules (5)
Judgment of the calendar
The idea of quicksort
The idea of jQuery
About the handling of Null
Docker monitoring-explaining the basics of basics-
About the description of Docker-compose.yml
Understand the basics of docker
The play of instantiating java.lang.Void
Explanation of the FizzBuzz problem
The basics of Swift's TableView
Median of the three values
The illusion of object orientation
Switch the version of bundler
About the behavior of ruby Hash # ==
[Java] Delete the elements of List
Continuation: The parable of OOP (omitted)
Qualify only part of the text
Understand the basic mechanism of log4j2.xml
About the basics of Android development
'% 02d' What is the percentage of% 2?
[Rails] Check the contents of the object
Replace the contents of the Jar file
[Java version] The story of serialization
Check the version of Cent OS
[Swift] Change the textColor of UIDatePicker
[Ruby] See the essence of ArgumentError
Explanation of the order of rails routes
I read the source of ArrayList I read
The basics of SpringBoot + MyBatis + MySQL
Note on the path of request.getRequestDispatcher
Try Hello World with the minimum configuration of Heroku Java spring-boot
The basic basis of Swift dialogs
The basic basis of Swift's Delegate
I read the source of Integer
This and that of the JDK
Check the migration status of rails
The story of @ViewScoped consuming memory
Filter the fluctuations of raw data
Explaining the columns of Spree :: Taxonomy
A memorandum of the FizzBuzz problem
I read the source of Long
Official logo list of the service
Explain the column of Spree :: Product
Various methods of the String class
About the role of the initialize method
Think about the 7 rules of Optional
Get the ID of automatic numbering
I read the source of Short
I read the source of Byte
Order of processing in the program
I read the source of String
The origin of Java lambda expressions
[Ruby] Display the contents of variables
Filter the result of BindingResult [Spring]
Summary about the introduction of Device
Remote debugging of the Cognos SDK