Monad 定义

非正式地,monad 是元素的容器,标记为 F[_],包含 2 个函数:flatMap(用于转换此容器)和 unit(用于创建此容器)。

常见的库示例包括 List[T]Set[T]Option[T]

正式定义

Monad M 是一个参数类型 M[T],有两个操作 flatMapunit,例如:

trait M[T] {
  def flatMap[U](f: T => M[U]): M[U]
}

def unit[T](x: T): M[T]

这些功能必须满足三个法则:

  1. 相关性(m flatMap f) flatMap g = m flatMap (x => f(x) flatMap g)
    也就是说,如果序列不变,你可以按任何顺序应用这些术语。因此,将 m 应用于 f,然后将结果应用于 g 将产生与将 f 应用于 g 相同的结果,然后将 m 应用于该结果。
  2. 左单位unit(x) flatMap f == f(x)
    也就是说,x 的单位 monad 平面映射到 f 相当于将 f 应用于 x
  3. 正确的单位m flatMap unit == m
    这是一个’身份’:任何与单位平面映射的单子会返回一个等同于自身的单子。

示例

val m = List(1, 2, 3)
def unit(x: Int): List[Int] = List(x)
def f(x: Int): List[Int] = List(x * x)
def g(x: Int): List[Int] = List(x * x * x)
val x = 1
  1. 相关性
(m flatMap f).flatMap(g) == m.flatMap(x => f(x) flatMap g) //Boolean = true
//Left side:
List(1, 4, 9).flatMap(g) // List(1, 64, 729)
//Right side:
 m.flatMap(x => (x * x) * (x * x) * (x * x)) //List(1, 64, 729)
  1. 左单位
unit(x).flatMap(x => f(x)) == f(x)
List(1).flatMap(x => x * x) == 1 * 1
  1. 正确的单位
//m flatMap unit == m
m.flatMap(unit) == m
List(1, 2, 3).flatMap(x => List(x)) == List(1,2,3) //Boolean = true

标准收藏品是 Monads

大多数标准集合是 monad(List[T]Option[T])或 monad-like(Either[T]Future[T])。这些集合可以很容易地在 for 理解中组合在一起(这是编写 flatMap 变换的等效方式):

val a = List(1, 2, 3)
val b = List(3, 4, 5)
for {
  i <- a
  j <- b
} yield(i * j)

以上相当于:

a flatMap {
  i => b map {
    j => i * j
  }
}

因为 monad 保留了数据结构并且只对该结构中的元素起作用,所以我们可以使用无穷无尽的链 monadic 数据结构,如此处所示的 for-comprehension。