/
core.clj
127 lines (102 loc) · 2.73 KB
/
core.clj
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
(ns hashlog.core)
(declare apply-cond)
(defn exists [key]
(fn [hash] (contains? hash key)))
(defn is [key v]
(fn [hash] (= (hash key) v)))
(defn every [cond-coll]
(fn [hash] (every? #(apply-cond % hash) cond-coll)))
(defn multiply [key num]
(fn [hash] (* (hash key) num)))
(defn sum [keys]
(fn [hash] (apply + (map #(hash %) keys))))
(defn value [key]
(fn [hash] (hash key)))
(defn apply-cond [f hash]
(let [pred (cond (vector? f) (every f)
(not (fn? f)) (exists f)
:else f)]
(pred hash)))
(defn next-hash [input-hash logs]
(reduce (fn [hash {condf :cond, key :key, val :val}]
(let [v (cond (fn? val) (val hash)
:else val)]
(if (apply-cond condf hash)
(assoc hash key v)
hash)))
input-hash
logs))
(defn hash-seq [init-hash logs]
(let [eval-seq (iterate #(let [next (next-hash (:hash %) logs)]
{:hash next
:before (conj (:before %) (:hash %))})
{:hash init-hash
:before #{}})]
(map :hash
(take-while #(not (contains? (:before %) (:hash %)))
eval-seq))))
(defn query [hseq q]
(if-let [hash (last (filter #(contains? % q) hseq))]
(hash q)
'no-answer))
(comment
(def buy-fruits
{:apple 2
:orange 4
})
(def fruits-price
[
{:cond :apple
:key :priceOfApple
:val (multiply :apple 100)
}
{:cond :orange
:key :priceOfOrange
:val (multiply :orange 80)
}
{:cond [:priceOfApple :priceOfOrange]
:key :price
:val (sum [:priceOfApple :priceOfOrange])
}
])
(def fruits-price-discount
(conj fruits-price
{:cond [:price (is :hasCoupon true)]
:key :discountPrice
:val (multiply :price 0.9)
}
{:cond [:price (is :hasCoupon false)]
:key :discountPrice
:val (value :price)
}
))
;; 価格計算HashMapのシーケンスを作る
(def price-seq (hash-seq buy-fruits fruits-price))
;; 2つ目以降は結果が変わらないのでdropされている
(take 3 price-seq)
;({:orange 4, :apple 2}
; {:orange 4,
; :apple 2,
; :priceOfApple 200,
; :price 520,
; :priceOfOrange 320})
;; 価格を知る
(query price-seq :price)
;=> 520
;; クーポン有りの価格計算
(def price-seq2 (hash-seq
(assoc buy-fruits :hasCoupon true)
fruits-price))
(take 3 price-seq2)
;({:orange 4, :hasCoupon true, :apple 2}
; {:orange 4,
; :hasCoupon true,
; :discountPrice 468.0,
; :apple 2,
; :priceOfApple 200,
; :price 520,
; :priceOfOrange 320})
(query price-seq2 :discountPrice)
;=> 468.0
;; 520の1割引
)