gpt4 book ai didi

clojure - 为什么 Clojure 的 `let` 和 `for` 都是单子(monad)?

转载 作者:行者123 更新时间:2023-12-04 00:00:41 25 4
gpt4 key购买 nike

In this discussion Brian Marick指出 let for 是 Clojure 中的单子(monad):

That said, the really general-purpose monads tend to get written into the language as special forms. Clojure's let and for are both monads, but you don't need to know that to use them.



这是 let
user=> (let [c (+ 1 2)
[d e] [5 6]]
(-> (+ d e) (- c)))
8

这是 for
user=> (for [x [0 1 2 3 4 5]
:let [y (* x 3)]
:when (even? y)]
y)
(0 6 12)

我的问题是: 为什么 Clojure 的 letfor两个单子(monad)?

最佳答案

为什么 Clojure 的 letfor两个单子(monad)?

他们不是。

Clojure 的 letfor不是单子(monad),因为它们没有完全暴露它们的单子(monad)共同结构。它们更像是糖 jail 里的单子(monad)。

什么是单子(monad)?

用 Clojure 的说法,一个 monad 可以被描述为一个 Monad 协议(protocol)的具体化,它的函数被期望以某些明确定义的方式相互运行并在具体化类型上运行。这并不是说 monad 必须用 defprotocol 来实现。 , reify , 和 friend ,但这给出了这个想法,而不必谈论类型类或类别。

(defprotocol Monad 
(bind [_ mv f])
(unit [_ v]))

(def id-monad
(reify Monad
(bind [_ mv f] (f mv))
(unit [_ v] v)))

(def seq-monad
(reify Monad
(bind [_ mv f] (mapcat f mv))
(unit [_ v] [v])))



Monad 使用起来可能很困惑
(bind seq-monad (range 6) (fn [a] 
(bind seq-monad (range a) (fn [b]
(unit seq-monad (* a b))))))
;=> (0 0 2 0 3 6 0 4 8 12 0 5 10 15 20)

不加一点糖
(defn do-monad-comp 
[monad body return]
(reduce
(fn [a [exp sym]] (list 'bind monad exp (list 'fn [sym] a)))
(list 'unit monad return)
(partition 2 (rseq body))))

(defmacro do-monad [monad body return]
(do-monad-comp monad body return))

这更容易写
(do-monad seq-monad 
[a (range 6)
b (range a)]
(* a b))
;=> (0 0 2 0 3 6 0 4 8 12 0 5 10 15 20)

但这不就是……吗?

这看起来很像
(for
[a (range 6)
b (range a)]
(* a b))
;=> (0 0 2 0 3 6 0 4 8 12 0 5 10 15 20)


(do-monad id-monad 
[a 6
b (inc a)]
(* a b))
;=> 42

看起来很像
(let
[a 6
b (inc a)]
(* a b))
;=> 42

所以,是的, for就像序列 monad 和 let就像身份单子(monad),但在糖化表达的范围内。

但这并不是所有的单子(monad)。

Monads 的结构/契约可以以其他方式被利用。许多有用的单子(monad)函数可以仅根据 bind 来定义。和 unit , 例如
(defn fmap 
[monad f mv]
(bind monad mv (fn [v] (unit monad (f v)))))

这样它们就可以与任何 monad 一起使用
(fmap id-monad inc 1)
;=> 2

(fmap seq-monad inc [1 2 3 4])
;=> (2 3 4 5)

这可能是一个相当微不足道的例子,但更普遍/更强大的 monad 可以以统一的方式组合、转换等,因为它们具有共同的结构。 Clojure 的 letfor不要完全公开这个通用结构,因此不能完全参与(以通用方式)。

关于clojure - 为什么 Clojure 的 `let` 和 `for` 都是单子(monad)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21752258/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com