首页 | 新闻 | 新品 | 文库 | 方案 | 视频 | 下载 | 商城 | 开发板 | 数据中心 | 座谈新版 | 培训 | 工具 | 博客 | 论坛 | 百科 | GEC | 活动 | 主题月 | 电子展
返回列表 回复 发帖

深入解析 Monad(4)Monad 的定义

深入解析 Monad(4)Monad 的定义

Monad        的定义现在回到函数 increase 和 decrease。从范畴论的角度出发,我们考虑下面一个范畴。该范畴中的对象仍然是 int 和 bool 等类型,但是其中的态射不再是简单的如        increase 和 decrease 这样的函数,而是把这些函数通过类似从 increase 到 increase1        这样的方式转换之后的函数。范畴中的态射必须是可以组合的,而这些函数的组合是通过调用类似 doCompose        这样的函数完成的。这样就满足了范畴的第一条原则。而第二条原则也很容易满足,只需要把参数 x 的值设为        0,就可以得到组合的基本单元。由此可以得出,我们定义了一个新的范畴,而这个范畴就叫做 Kleisli 范畴。每个 Kleisli 范畴所使用的函数转换方式是独特的。  中的示例使用 Tuple2 来保存 count 的增量。与之对应的,Kleisli          范畴中对态射的组合方式也是独特的,类似清单 6 中的 doCompose 函数。
在对 Kleisli 范畴有了一个直观的了解之后,就可以对 Monad 给出一个形式化的定义。给定一个范畴 C 和 endofunctor m,与之相对应的 Kleisli        范畴中的对象与范畴 C 相同,但态射是不同的。K 中的两个对象 a 和 b 之间的态射,是由范畴 C 中的 a 到 m(b) 的态射来实现的。注意,Kleisli 范畴 K        中的态射箭头是从对象 a 到对象 b 的,而不是从对象 a 到 m(b)。如果存在一种传递的组合方式,并且每个对象都有组合单元箭头,也就是满足范畴的两大原则,那么这个        endofunctor m 就叫做 Monad。
一个 Monad 的定义中包含了 3 个要素。在定义 Monad 时需要提供一个类型构造器 M 和两个操作 unit 和 bind:
  • 类型构造器的作用是从底层的类型中创建出一元类型(monadic type)。如果 M 是 Monad 的名称,而 t 是数据类型,则 M t 是对应的一元类型。
  • unit 操作把一个普通值 t 通过类型构造器封装在一个容器中,所产生的值的类型是 M t。unit 操作也称为 return 操作。return 操作的名称来源于          Haskell。不过由于 return 在很多编程语言中是保留关键词,用 unit 做名称更为合适。
  • bind 操作的类型声明是 (M t)→(t→M u)→(M u)。该操作接受类型为 M t 的值和类型为 t → M u 的函数来对值进行转换。在进行转换时,bind          操作把原始值从容器中抽取出来,再应用给定的函数进行转换。函数的返回值是一个新的容器值 M u。M u 可以作为下一次转换的起点。多个 bind          操作可以级联起来,形成处理流水线。
如果只看 Monad 的定义,会有点晦涩难懂。实际上  中的示例就是一种常见的 Monad,称为        Writer Monad。下面我们结合 Java 代码来看几种常见的 Monad。
返回列表