Map 映射并减少Clojure的Monad。。。那就来一杯Juxt Monad怎么样?

Map 映射并减少Clojure的Monad。。。那就来一杯Juxt Monad怎么样?,map,clojure,monads,reduce,Map,Clojure,Monads,Reduce,在学习Clojure的过程中,我花了很多时间试图理解单子——它们是什么以及我们如何使用它们。。。。没有太多的成功。然而,我发现了一个优秀的“蒙娜斯为傻瓜”视频系列——由布赖恩·马里克为Clojure制作 到目前为止,我对单子的理解是,它有点像宏,因为它允许以易于阅读的形式编写一组语句,但单子的形式要正式得多。我的观察仅限于两个例子: 1。身份单子(或“let”单子)取自 我们希望填写的表格为: (let [a 1 b (inc a)] (* a b)) (for [a (r

在学习Clojure的过程中,我花了很多时间试图理解单子——它们是什么以及我们如何使用它们。。。。没有太多的成功。然而,我发现了一个优秀的“蒙娜斯为傻瓜”视频系列——由布赖恩·马里克为Clojure制作

到目前为止,我对单子的理解是,它有点像宏,因为它允许以易于阅读的形式编写一组语句,但单子的形式要正式得多。我的观察仅限于两个例子:

1。身份单子(或“let”单子)取自

我们希望填写的表格为:

(let [a  1
      b  (inc a)]
  (* a b))
(for [a (range 5)
      b (range a)]
  (* a b))
对应的单子是

(domonad identity-m
    [a  1
     b  (inc a)]
 (* a b))
(domonad sequence-m
  [a (range 5)
   b (range a)]
  (* a b))
2。单子序列(或“for”单子)取自

我们希望填写的表格是:

(let [a  1
      b  (inc a)]
  (* a b))
(for [a (range 5)
      b (range a)]
  (* a b))
对应的单子是

(domonad identity-m
    [a  1
     b  (inc a)]
 (* a b))
(domonad sequence-m
  [a (range 5)
   b (range a)]
  (* a b))
Clojure中的单子定义

查看源代码,使用clojure monads库-:

同一性单子:

user=> (source identity-m)
(defmonad identity-m
  [m-result identity
   m-bind   (fn m-result-id [mv f]
              (f mv))
  ])
序列单体:

user=> (source sequence-m)
(defmonad sequence-m
   [m-result (fn m-result-sequence [v]
               (list v))
    m-bind   (fn m-bind-sequence [mv f]
               (flatten* (map f mv)))
    m-zero   (list)
    m-plus   (fn m-plus-sequence [& mvs]
               (flatten* mvs))
    ])
所以我的结论是,monad是一种广义的高阶函数,它接受一个输入函数和输入值,添加自己的控制逻辑,并吐出一个可以在“domonad”块中使用的“东西”

问题1

最后,对于问题:我想学习如何编写monad,并说我想编写一个模仿clojure中“map”形式的“map monad”:

(domonad map-m
  [a [1 2 3 4 5]
   b [5 6 7 8 9]]
  (+ a b))
应该相当于

(map + [1 2 3 4 5] [5 6 7 8 9])
并返回值

[6 8 10 12 14]
如果我看一下源代码,它会给我类似于identity-m和sequence-m的东西:

user=> (source map-m)
(defmonad map-m
   [m-result ...
    m-bind   ...
    m-zero   ...
    m-plus   ...
    ])
问题2

我还希望能够定义“reduce-m”,这样我就可以写:

(domonad reduce-m
  [a [1 2 3 4 5]]
  (* a))
这可能会给我1 x 2 x 3 x 4 x 5=120或

(domonad reduce-m
  [a [1 2 3 4 5]
   b [1 2 3 4 5]]
  (+ a b))
给我(1+2+3+4+5)+(1+2+3+4+5)=30

最后 我是否也能够编写一个模仿juxt函数的“juxt monad”,但不是为绑定传递值,而是传递一组函数:

(domonad juxt-m
  [a #(+ % 1)
   b #(* % 2)]
  '([1 2 3 4 5] b a) )
给予

可能,我可以用宏完成所有这些事情,所以我真的不知道这些“单子”有多有用,或者它们是否被认为是“单子”。。。有了互联网上的所有资源,在我看来,如果我想正确地学习单子,我必须学习Haskell,而现在,学习另一种句法形式太难了。我想我找到了一些可能相关的链接,但对我来说太神秘了


请有人给我点光

你的问题不是单子的类型。它们看起来更像是一种语法糖,你可以使用宏来完成,我甚至不建议你这样做,因为map、reduce等都是简单的函数,没有必要让它们的界面复杂化

之所以这些情况不是单子,是因为单子是一种放大值,包裹正常值。在map和reduce的情况下,您使用的向量不需要放大就可以在map或reduce中工作

尝试在domoand表达式上进行macroexpand将对您有所帮助。 例如:sequence monad示例应扩展为:

(bind (result (range 5)) 
   (fn [a] 
      (bind (result (range a))
        (fn [b] (* a b))
   )))
其中bind和result是序列monad m-bind和m-result中定义的函数。
因此,基本上,domand后面的向量表达式被嵌套,向量后面的表达式被按原样使用,在上述情况下(*ab)被按原样调用(只是a和b值由monad提供)。在您的map monad示例中,向量表达式应该是原样的,最后一个表达式(+ab)应该以某种方式表示(map+ab),这不是monad应该做的。

我找到了一些非常好的monad资源:

  • (吉姆·杜伊(Jim Duey)的《单子指南》(monad Guide),该指南真正深入了单子的基本定义)
  • (一大堆单子上的论文)
  • (关于范畴理论的演讲,我只听了一半)
因此,根据Jim的指南,他给出了“bind-m”和“reduce-m”函数定义的三条公理:

身份 第一个单子定律可以写成

(m-bind(m-result x)f)等于(fx)

这意味着无论m-result对x做了什么,使其成为一元值,m-bind都会在将f应用于x之前撤消。关于m-bind,m-result有点像一个恒等函数。或者在范畴论术语中,它的单位。这就是为什么有时你会看到它被命名为“单位”

反向身份第二个单子定律可以写成

(m-bind mv m-result)等于mv,其中mv为一元值

这条法律有点像是对第一条法律的补充。它基本上确保了m-result是一个一元函数,并且无论m-bind对一元值做什么来提取一个值,m-result都会撤消以创建一元值

关联性 第三个单子定律可以写成

(m-bind(m-bind mv f)g)等于(m-bind mv(fn[x](m-bind(f x)g))) 其中f和g是一元函数,mv是一元值

这条定律的意思是,f是否应用于mv,然后g是否应用于结果,或者是否从f和g的组合中创建一个新的一元函数,然后应用于mv,都无关紧要。在任一顺序中,结果值都是相同的一元值。换句话说,m-bind是左关联和右关联的


在本文中,他给出了一个单子,它将集合作为输入,而不是列表。将完成所有示例…

您的示例不是单子。单子表示可组合的计算步骤。在平凡的恒等式单子中,计算步骤只是一个表达式求值

在maybe monad中,步骤是一个可能成功或失败的表达式

在序列monad中,step是一个表达式,它生成数量可变的结果(序列的元素)

在作者monad中,计算步骤