在观看本教程后,我正在研究一些自己的示例:http://www.infoq.com/presentations/Why-is-a-Monad-Like-a-Writing-Desk并阅读http://blog.sigfpe.com/2006/08/you-could-have-invented-monads-and.html。
我提出了以下功能:
(defn unit [v s] (fn [] [v s])) (defn bind [mv f] (f (mv))) (defn inc+ [mv] (bind mv (fn [[v s]] (let [r (inc v)] (unit r (apply str (concat s " inc+(" (str r) ")"))))))) (defn double+ [mv] (bind mv (fn [[v s]] (let [r (* 2 v)] (unit r (apply str (concat s " double+(" (str r) ")"))))))) (defn triple+ [mv] (bind mv (fn [[v s]] (let [r (* 3 v)] (unit r (apply str (concat s " triple+(" (str r) ")"))))))) ;; Testing: ((-> (unit 1 "1 ->") inc+)) ;; => [2 "1 -> inc+(2)"] ((-> (unit 3 "3 ->") inc+ double+ inc+)) ;; => [27 "3 -> inc+(4) double+(8) inc+(9) triple+(27)"]
我希望重写bind来封装方法inc + double +和triple +的模式,并获得与以前相同的输出。怎么会这样做?
答案 0 :(得分:1)
我分两个阶段想出来:
(defn unit [v s] (fn [] [v s])) (defn bind [mv f] (let [[iv is] (mv) [av as] (f iv)] (unit av (str is " " as)))) (defn inc+ [mv] (bind mv (fn [v] [(inc v) (str " inc+(" (inc v) ")")]))) (defn double+ [mv] (bind mv (fn [v] [(inc v) (str " double+(" (inc v) ")")]))) (defn triple+ [mv] (bind mv (fn [v] [(inc v) (str " triple+(" (inc v) ")")])))
然后:
(defn unit [v s] (fn [] [v s])) (defn bind [mv f] (let [[v s] (mv) r (f v) xs (->> (str (type f)) (re-find #"\$([^\$]*)\$?") second) ] (unit r (str s " " (str xs "(" r ")"))))) (defn inc+ [mv] (bind mv inc)) (defn double+ [mv] (bind mv #(* 2 %))) (defn triple+ [mv] (bind mv #(* 3 %))) ((-> (unit 3 "3 ->") inc+ double+ inc+ triple+)) ;;=> [27 "3 -> inc_PLUS_(4) double_PLUS_(8) inc_PLUS_(9) triple_PLUS_(27)"]
所以看看其他Monad教程,特别是http://channel9.msdn.com/Shows/Going+Deep/Brian-Beckman-Dont-fear-the-Monads,我想我现在理解核心原则。 'Monads'真的就是能够重用我们手头的功能。 unit
和bind
必须设计为协同工作。然后,将函数组合在一起几乎是微不足道的。
然后再写一个do-m
运算符的抽象:
(defn unit [v s] (fn [] [v s])) (defn bind [mv f] (let [[v s] (mv) r (f v) xs (->> (str (type f)) (re-find #"\$([^\$]*)\$?") second) ] (unit r (str s " " (str xs "(" r ")"))))) (defn double [v] (* 2 v)) (defn triple [v] (* 3 v)) (defn do-m [v & fs] (let [fn-ms (map #(fn [mv] (bind mv %)) fs)] (((apply comp (reverse fn-ms)) (unit v (str v "->")))))) (do-m 3 inc double triple) ;;=> [24 "3 -> inc(4) double(8) triple(24)"]
这是另一种写入实现相同结果的方法,请注意,更改是取出unit
中的lambda函数以及bind
和do-m
的相关调用。
(defn unit [v s] [v s]) (defn bind [mv f] (let [[v s] mv r (f v) xs (->> (str (type f)) (re-find #"\$([^\$]*)\$?") second) ] (unit r (str s " " (str xs "(" r ")"))))) (defn double [v] (* 2 v)) (defn triple [v] (* 3 v)) (defn sqrt [v] (Math/sqrt v)) (defn do-m [v & fs] (let [fn-ms (map #(fn [mv] (bind mv %)) fs)] ((apply comp (reverse fn-ms)) (unit v (str v " ->"))))) (do-m 3 inc double double triple triple sqrt) ;; => [12.0 "3 -> inc(4) double(8) double(16) triple(48) triple(144) sqrt(12.0)"]