1. 程式人生 > >【函式式】Monads模式初探——Option Monad

【函式式】Monads模式初探——Option Monad

Option Monad

Scala中的Option是一個Monad實現。
Option的簡化版定義如下:

sealed abstract class Option[+A] {
  def isEmpty: Boolean

  def get: A

  def map[B](f: A => B): Option[B] =
    if(isEmpty) None else Some(f(this.get))

  def flatMap[B](f: A => Option[B]): Option[B] =
    if(isEmpty) None else f(this
.get) } final case class Some[+A](x: A) extends Option[A] { def isEmpty: false def get = x } final case class None extends Option[Nothing] { def isEmpty = true def get = throw new NoSuchElementException("None.get") }

程式碼中,Option定義了flatMap,Some和None都被定義為case class,所以其名字就是構造器,無需定義unit函式。
Option可以看成是隻有一個元素的容器:

  • map的工作就是對僅有的一個元素進行f呼叫,然後將結果打包成Option
  • flatMap的工作是對一個元素進行f呼叫,產生的結果已經是Option例項,並且沒有其他的結果需要flatten

None的存在是唯一的插曲,map和flatMap對於None要做的額外工作就是檢查自己是不是None,如果是,則直接返回None。因為None表示一個空的容器,因此不能進行其他的計算。

用Monad規則驗證Option

對於Option,unit(x) == Some(x)。下面是Option的flatMap構造:

def flatMap[U](f: T => Option[U])
:
Option[U] = this match { case Some(x) => f(x) case None => None }

我們先證明Some(x) flatMap f == f(x)

Some(x) flatMap f
== Some(x) match {
case Some(x) => f(x)
case None => None
}
== f(x)

然後我們證明opt flatMap Some == opt

opt flatMap Some
== opt match {
case Some(x) => Some(x)
case None => None
}
== opt
這裡,我們看到對一個Option物件opt進行flatMap操作,
其中對映函式式Some建構函式時,返回的是初始時的opt

我們還要證明opt flatMap f flatMap g == opt flatMap (x => f(x) flatMap g)

opt flatMap f flatMap g
== opt match { case Some(x) => f(x) case None => None}
match { case Some(y) => g(y) case None => None}
如果將第二個match表示式嵌入第一個match表示式中,將得到
== opt match {
case Some(x) =>
f(x) match {case Some(y) => g(y) case None => None}
case None =>
None match {case Some(y) => g(y) case None => None}
}
== opt match {
case Some(x) =>
f(x) match {case Some(y) => g(y) case None => None}
case None => None
}
== opt match {
case Some(x) => f(x) flatMap g
case None => None
}
== opt flatMap (x => f(x) flatMap g)