Haskellモナドトランスフォーマー(4)
モナドトランスフォーマーはモナドの結合を簡単にするモナドの、特別な種類です。例えば、ReaderT Env IO aはEnv型の環境から読み取り、IOを行い、型aを返すことができる計算です。モナドトランスフォーマーの型コンストラクタはモナドのそれにパラメータ化されており、モナディックな型を生成します。モナドの仕組みがわかっていることを前提に話すので、もしかしたらわかりにくいかもしれません。そういったときは、Haskellのモナド(結構前の記事)あたりを見ていただけたらと思います。
トランスフォーマーは、元のモナドのいとこと見るのがよいです。例えば、ListTモナドは元のモナド、つまりListモナドのいとこです。一般的にモナドトランスフォーマーは、内側にあるモナドに値を渡していくために多少複雑になるだけで、他はそのいとこ(元のモナド)とほぼ同じように実装されています。
モナドテンプレートライブラリの基本的なモナドのそれぞれ全てに、トランスフォーマーが矛盾なく宣言されています。しかし、すべてのモナドが同じトランスフォーメーションを行なってくれるというわけではありません。ContTトランスフォーマーは(a -> r) -> rという継続を(a -> m r) -> m rという継続に変えます。StateTトランスフォーマーは違います。StateTトランスフォーマーはs -> (a, s)という関数を s -> m (a, s)と変えます。より一般的に言うと、モナドのトランスフォーマーを作る要素に魔法の入る余地はありません。それぞれのトランスフォーマーはトランスフォーマーでない型によって構成された文脈に応じて形を変えます。
基本的なモナド | トランスフォーマー | 元の型 | 結合後の型 |
---|---|---|---|
Error | ErrorT | Either e a | m (Either e a) |
State | StateT | s -> (a, s) | s -> m (a, s) |
Reader | ReaderT | r -> a | r -> m a |
Writer | WriterT | (a, w) | m (a, w) |
Cont | ContT | (a -> r) -> r | (a -> m r) -> m r |
上のテーブルでは、ほとんどのトランスフォーマーFooTは元のモナドFooと、結果の型をモナドmで包み込んでいるという点で異なります。Contモナドは2つの”結果”が方の中にありますが、ContTモナドはどちらのつながったモナドも包み込みます。言い方を変えると、基本的にはこれらは以下のような共通するものを持っています。
元の型 | 結合した型 |
---|---|
* | m * |
* -> * | * -> m * |
(* -> *) -> * | (* -> m *) -> m * |