みどりねこ日記

よくわからないけど、頑張りますよ。

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 *