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。