「モナドはメタファーではない」に関する補足

日本語訳 モナドはメタファーではない
原文 Monads Are Not Metaphors

原文が書かれたのはもう2年半くらい前ですが、いまだにたまにtweetされてたり、250くらいはてブがついてたり人気ありますね。で、説明中ででてくるコード例に関する補足というか、野暮なツッコミを思い出したので、書いておきます。
「野暮なツッコミ」といってる通り、「書いた本人はおそらく最初からわかっていたけれど(説明の都合上)あえて省略した部分」を説明する感じです。あと、わざとScalazを説明に使います。

firstNameとlastNameからfullNameを取得するコード例は、MonadではなくApplicative*1があれば十分

もとのコードは以下のようになってますが

def firstName(id: Int): Option[String] = ...    // fetch from database
def lastName(id: Int): Option[String] = ...
 
def fullName(id: Int): Option[String] = {
  firstName(id) bind { fname =>
    lastName(id) bind { lname =>
      Some(fname + " " + lname)
    }
  }
}

Scalaz*2 で書くとすれば、以下のように書けます

import scalaz._,Scalaz._

def firstName(id: Int): Option[String] = ???
def lastName(id: Int): Option[String] = ???

def fullName(id: Int): Option[String] =
  ^(firstName(id), lastName(id))(_ + " " + _)

もしくは

def fullName(id: Int): Option[String] =
  Apply[Option].apply2(firstName(id), lastName(id))(_ + " " + _)


念のため繰り返しておくと、書いた本人は上記のことわかってるだろうし、こんなことを言ってます


ScalazにおいてのMonadのsequence函数

まず、Scalaz7に

def sequence[M[_], A](ms: List[M[A]])(implicit tc: Monad[M]): M[List[A]]

というシグネチャ函数は存在しません。代わりにApplicativeに以下のようなものがあります

def sequence[A, G[_]: Traverse](as: G[F[A]]): F[G[A]] =

https://github.com/scalaz/scalaz/blob/v7.0.0/core/src/main/scala/scalaz/Applicative.scala#L39

結論を先に言ってしまうと、 "「モナドはメタファーではない」の中で説明されているsequence函数*3 " は、
Scalazにおいては、一般化された形でのみ存在しています。


ちなみに、Haskellの場合はApplicativeに直接該当するメソッドがあるわけではなく、TraversableにsequenceAというメソッドがあります。 http://www.haskell.org/ghc/docs/latest/html/libraries/base/Data-Traversable.html#v:sequenceA


Scalazに戻ると、「一般化された形」とはつまり、これ

def sequence[A, G[_]: Traverse](as: G[F[A]]): F[G[A]]

のGの型パラメータをListに固定すると

def sequence[A](as: List[F[A]]): F[List[A]]

となって、Scalazで定義されているsequence函数が、"「モナドはメタファーではない」の例ででてきたsequence函数" と同じになるということです。

(implicit tc: Monad[M])

の部分がなくなっているように見えるますが、「ScalazのApplicativeのメソッドとして定義」しているので、Fは自動的にApplicativeのインスタンスです。
なんだかちょっとややこしくなってきましたが、つまり
「ここで例に出てきたsequence函数も、Monadが必要ではなくApplicativeで十分」
という話です。

Haskellが、なぜMonadに直接

sequence :: Monad m => [m a] -> m [a]

というのがあったり、
Traversableに

sequenceA :: Applicative f => t (f a) -> f (t a)

sequence :: Monad m => t (m a) -> m (t a)

という似たようなものが2つあったりするのかは、誤解を恐れずにあえて一言で言うと「MonadがApplicativeを継承していなかった、という歴史的事情による産物」だと思います。


あと、「一般化された形」と言いましたが、それについてもうちょっと説明しておきます。"「モナドはメタファーではない」で出てきたsequence"の実装には、ListのfoldRightを使っています*4

*5 つまり「foldRight相当の機能をもつコンテナ」=> 「Traverseのtypeclassのインスタンスになるもの」ということなので、「sequence函数を一般化」した場合のシグネチャには

def sequence[A, G[_]: Traverse](as: G[F[A]]): F[G[A]]

というように、Traverseがでてくるわけです。


まとめ

というわけで、

の2点とも、結局MonadではなくApplicative (ry という話でした。
このように、(説明の都合上)わざとだったり、本人も気づいてなかったり、いずれにせよ
「実はMonadではなく、単にApplicativeで事足りる」
パターンが、Monadの説明の例として使われていることは他にも大量にあるので、みんな「モナド( ゚∀゚)彡 モナド( ゚∀゚)彡 」ばかり言わないで、もうちょっと意識してApplicativeの存在に気づけるようになるといいと思います。

*1:もっと正確にはApply

*2: 7.0.0 final

*3:Haskellにも同じものがある

*4: Haskellの場合も同様にfoldr https://github.com/ghc/packages-base/blob/ghc-7.6.3-release/Control/Monad.hs#L97-L103

*5:Traverseのtypeclass自体を説明すると長くなるので省略しますが