- あわせて読みたい
- 原文に対する Edward Kmett さんのコメント では
どういう場合に合成できるのか?Monadを合成するにはどういう方法があるのか?というのが書かれていたが、ページのリニューアルで、コメントが消えてしまった? - 合成できるモナド、モナドが合成できる時 同じく、 @everpeace さんによる、Monadの合成の話
- Edward Kmettさんがコメントで言及している「This was covered by Mark P. Jones back around 93.」というのが、おそらくこの論文 論文のpdf直リンク
- Moandが(一般的にすべての場合で合成できない) => よって Moand transformer が必要となる(?)わけですが、その Scala での Moand transformers についてのとてもわかり易い資料(videoとslide両方あり)
- HaskellでのMonadの合成の話? (Haskellでのこの辺りのさらにわかり易い資料があったらだれか教えて)
- 型コンストラクタの部分適用のイディオム知らない人は、 @yuroyoroさんが書いたものがあります
- 原文に対する Edward Kmett さんのコメント では
- あきらかな誤訳などあれば、ここのコメントに書く、twitterで @xuwei_k にメンション送る、pull req投げるなどでお知らせください。
-
-
Save xuwei-k/3769691 to your computer and use it in GitHub Desktop.
http://blog.tmorris.net/monads-do-not-compose/
わたしは、Scalaのメーリングリストで、「モナドは合成できない」といいました。これは正確にはどういう意味でしょうか?たぶん、以下が答えです。
まず最初に、Functor
、Applicative
そして Monad
のインターフェイスから話をはじめましょう。
trait Functor[F[_]] {
def fmap[A, B](f: A => B, a: F[A]): F[B]
}
trait Applicative[F[_]] extends Functor[F] {
def ap[A, B](f: F[A => B], a: F[A]): F[B]
def point[A](a: A): F[A]
override final def fmap[A, B](f: A => B, a: F[A]) =
ap(point(f), a)
}
trait Monad[F[_]] extends Applicative[F] {
def flatMap[A, B](f: A => F[B], a: F[A]): F[B]
override final def ap[A, B](f: F[A => B], a: F[A]) =
flatMap((ff: A => B) => fmap((aa: A) => ff(aa), a), f)
}
主張を言い換えてみましょう。
- Functor は合成できる
- Applicative は合成できる
- Monad は合成できない
では、1と2について話しましょう。この文脈で、「Xが合成できる」とはなにを意味するでしょうか?この疑問について、さらに簡潔に答えてみましょう。
「Xが合成できる」とは、あるXについて、以下のようなシグネチャの関数が書けるということを意味します。
def XCompose[M[_], N[_]](implicit mx: X[M], nx: X[N]):
X[({type λ[α]=M[N[α]]})#λ]
この戻り値型は、わかりにくく見えるかもしれません。しかし、これは単にScalaにおいて、型コンストラクタを部分適用する方法に過ぎません。 It is essentially the X type constructor applied to the composition of M and N and followed by a type variable just like M and N itself (kind * -> *). 私達の主張をテストしてみましょう。
Functorは合成できます。つまり、以下のようなシグネチャの関数を書くことができます
def FunctorCompose[M[_], N[_]]
(implicit mx: Functor[M], nx: Functor[N]):
Functor[({type λ[α]=M[N[α]]})#λ]
やってみましょう!
new Functor[({type λ[α]=M[N[α]]})#λ] {
def fmap[A, B](f: A => B, a: M[N[A]]) =
mx.fmap((na: N[A]) => nx.fmap(f, na), a)
}
2つのFunctorを合成することができました。1の主張について実証しました。では、2についてはどうでしょうか?やってみましょう!
def ApplicativeCompose[M[_], N[_]]
(implicit ma: Applicative[M], na: Applicative[N]):
Applicative[({type λ[α]=M[N[α]]})#λ] =
new Applicative[({type λ[α]=M[N[α]]})#λ] {
def ap[A, B](f: M[N[A => B]], a: M[N[A]]) = {
def liftA2[X, Y, Z](f: X => Y => Z, a: M[X], b: M[Y]): M[Z] =
ma.ap(ma.fmap(f, a), b)
liftA2((ff: N[A => B]) => (aa: N[A]) => na.ap(ff, aa), f, a)
}
def point[A](a: A) =
ma point (na point a)
}
ちょっと、本質的ではない(型についての)記述が多いですが、しかし、このようにScalaは大量のボイラープレートを要求することが多いです。うまくいけば、あなたは 「2つの Applicative Functor を合成する」ということが、何を意味するのかを理解することができるでしょう。では、Monadの話に戻りましょう。本質的に、「あなたは、以下のようなMonadを合成する関数を記述することが不可能」ということです。
def MonadCompose[M[_], N[_]](implicit ma: Monad[M], na: Monad[N]):
Monad[({type λ[α]=M[N[α]]})#λ]
これがお役に立てれば幸いです!
についてですが、文法的には、itは前文のitと同じものを指していていて、applied to〜とfollowed by〜が、the X type constructorにかかっています。
なので直訳すると、
これは本質的には、MとNの合成に適合し、そして(カインドが * -> *である)ちょうどMやNそれ自身のような型変数に準ずる、X型コンストラクタです。
な感じかと思います。
意味合い的には、
「これ(前文からのit)」は、本質的に、MとNの合成を表し、MとNと同じ1階カインドである、X型コンストラクタ、だよと言いたいのだと思います。