瞎扯淡 Reddit 上的 Ruby 程序员 monad 入门

fsword · 2016年02月05日 · 最后由 hammer 回复于 2016年03月28日 · 2641 次阅读

简洁有力,比什么“自函子范畴上的一个幺半群”的说法实用多了

https://www.reddit.com/r/ruby/comments/448b62/teaching_monads_to_rubyists_without_analogies/

其实就是 Array 这种纯容器不能延时求值,然后要给这个容器加个函数作为接口: 访问 → f [] 之后对这个数组的操作都叠在 f 上,不 touch [], 等到求值的时候再把 f 应用到[]

个人理解

前两年因为到 monad 卡住了没学会 haskell,春节这几天要不要再试试呢

#1 楼 @mizuhashi 延迟求值和 monad 没有联系

可以看看 The category design pattern http://www.haskellforall.com/2012/08/the-category-design-pattern.html

functor 是 category 之间的函数 自函子 endofunctor 意思是定义域和值域都是同一个 category, 基本等于废话可以不管。

有单位元,运算符又满足结合律,就是 幺半群 monoid 的定义. monad 中,单位元是 return, 满足结合律的运算符是 bind (>>=)

换句话说,monad 是定义在函数上的代数结构,它有单位元,又有满足结合律的运算符。

如果在 Ruby 数组上找 monad, 那么以 [] 为单位元,以 .flat_map 为满足结合律的运算符,就构成一个 Array Monad. 例如把这段 Haskell 代码贴进 ghci

let a = 2
let b = [3, 4]
let c = ['a', 'b']
:{
do
  x <- return a
  y <- b
  z <- c
  return (x, y, z)
:}

执行结果是 [(2,3,'a'),(2,3,'b'),(2,4,'a'),(2,4,'b')]. 注意 do notation 其实是一个让你省略括号和缩进的语法糖,再把 return 换成 [], 解除语法糖后是这样的意思:

[a] >>= \x ->
  b >>= \y ->
    c >>= \z ->
      [(x, y, z)]

那么对应 Ruby 代码是这样:

a = 2
b = [3, 4]
c = ['a', 'b']
[a].flat_map do |x|
  b.flat_map do |y|
    c.flat_map do |z|
      [[x, y, z]]
    end
  end
end

执行结果是 [[2, 3, "a"], [2, 3, "b"], [2, 4, "a"], [2, 4, "b"]]

如果在 Ruby 对象上找 monad, 那么以 .itself 为单位元,以 .try 为满足结合律的运算符,那就构成一个 Maybe Monad

具体例子留作练习哈

有各种各样找 monad 的方式,但只要记住 "自函子上的幺半群", 没有一个能逃出你的眼睛...

#4 楼 @luikore

我描述的是 functor 吧,monad 也是从类似的想法衍生出来的吧,就是先串函数,不碰 Just https://blog.oyanglul.us/javascript/functional-javascript.html 相关的东西是在这看的,但不知对不对,可以批判一下。。

#6 楼 @mizuhashi functor 没那么玄乎,认为它是函数上的函数就可以了...

wadler:一个单子(Monad)说白了不过就是自函子范畴上的一个幺半群而已。 品味了好久 ....

需要 登录 后方可回复, 如果你还没有账号请 注册新账号