为什么Clojure的`let`和`for`两个monad? [英] Why are Clojure's `let` and `for` both monads?

查看:148
本文介绍了为什么Clojure的`let`和`for`两个monad?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在本讨论中, Brian Marick 指出 for 是Clojure中的monads:


也就是说,真正的通用单词往往会以特殊形式写入语言。 Clojure的 let 都是monads,但你不需要知道使用它们。


这是 let

  user => (let [c(+ 1 2)
[de] [5 6]]
( - >(+ de)( - c)))
8

这是 for

  user => (对于[x [0 1 2 3 4 5] 
:let [y(* x 3)]
:when(even?y)]
y)
我的问题是:为什么Clojure的 let

code> and for 两个单子?

解决方案

p> 为什么Clojure的两个单子?



他们不是。



Clojure的 let 代表不是monad,因为他们不完全暴露他们的Monadic公共结构。


$ b

什么是monad?



>在Clojure中,monad可以被描述为Monad协议的参考,其功能预期彼此之间以及在某些明确定义的方式上的reized类型。这不是说,monad必须用 defprotocol reify 和朋友来实现,但这给出了想法而不必谈论类型类或类别。

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



Monads可能很乱。

 (bind seq-monad (范围6)(fn [a] 
(bind seq-monad(range a)(fn [b]
(unit seq-monad(* ab)))))
; => (0 0 2 0 3 6 0 4 8 12 0 5 10 15 20)

/ p>

 (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)]
(* ab))
; => (0 0 2 0 3 6 0 4 8 12 0 5 10 15 20)



这看起来很像

 (for 
[a(range 6)
b(range a)]
(* ab))
; => (0 0 2 0 3 6 0 4 8 12 0 5 10 15 20)

>

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

看起来很像

 (let 
[a 6
b(inc a)]
(* ab))
; => 42

所以, em>像序列monad和 let 是标识monad,但一个糖表达。



$ b

但这不是所有的单子都是。



Monads的结构/以其他方式利用。许多有用的一元函数可以仅用 bind unit 来定义,例如

 (defn fmap 
[monad f mv]
(bind monad mv(fn [v](unit monad(fv))) ))

这样它们就可以用于任何monad

 (fmap id-monad inc 1)
; => 2

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

这可能是一个相当微不足道的例子,由于它们的共同结构而以统一的方式组成,变换等。 Clojure的 let for 不会完全暴露这个公共结构,因此不能完全参与。


In this discussion Brian Marick makes the point that let and for are monads in Clojure:

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.

This is let

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

This is for

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

My question is: Why are Clojure's let and for both monads?

解决方案

Why are Clojure's let and for both monads?

They aren't.

Clojure's let and for are not monads because they do not fully expose their Monadic common structure. They are more like monads in a sugary prison.

What are monads?

In Clojure parlance, a monad could be described as reification of a Monad protocol whose functions are expected to behave with each other and on the reified type in certain well defined ways. This is not to say that monads have to be implemented with defprotocol, reify, and friends, but this gives the idea without having to talk about typeclasses or categories.

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

Sugar

Monads can be messy to use

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

Without some sugar

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

This is easier to write

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

But isn't that just...?

This looks a lot like

(for
  [a (range 6) 
   b (range a)] 
  (* a b))
;=> (0 0 2 0 3 6 0 4 8 12 0 5 10 15 20)

And

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

Looks a lot like

(let
  [a 6 
   b (inc a)] 
  (* a b))
;=> 42

So, yes, for is like the sequence monad and let is like the identity monad, but in the confines of a sugared expression.

But that's not all monads are.

Monads' structure/contract can be exploited in other ways. Many useful monadic functions can be defined in terms of only bind and unit, for example

(defn fmap 
  [monad f mv] 
  (bind monad mv (fn [v] (unit monad (f v)))))

So that they can be used with any monad

(fmap id-monad inc 1)
;=> 2

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

This might be a rather trivial example, but more generally/powerfully monads can be composed, transformed, etc. in a uniform way due to their common structure. Clojure's let and for don't fully expose this common structure, and so cannot fully participate (in a generic fashion).

这篇关于为什么Clojure的`let`和`for`两个monad?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆