いわゆるモナド変換子。定義はこんなの。
class MonadTrans t where
lift :: Monad m => m a -> t m a
以下の法則を満たす。
lift . return = return
lift (m >>= f) = lift m >>= (lift . f)
今まではなんとなくモナドの分配則で語るべき話かと思ってたんだけど、微妙に違うっぽい。具体的には、lift
はモナド間の射(monad morphism)として定義されている。確かに、求められる法則を見るとreturn
と(>>=)
の構造を保持するような規則と読み取れる。
ところで、モナドは関手なので、その間の射であれば自然変換であるべきだ。lift
も計算してみるときちんと自然変換になっている。f :: a -> b
について可換性を見てみる。
(lift . (fmap f)) mx
= lift(fmap f mx)
= lift(mx >>= (return . f)) -- fmapの定義
= lift mx >>= (lift . return . f) -- 法則2
= lift mx >>= (return . f) -- 法則1
= fmap f (lift mx) -- fmapの定義
= ((fmap f) . lift) mx
きちんと可換になっている。fmap
やreturn
が型が違うのに同じ表記になるのが見づらいが、要はξ_b ∘ Mf = Tf ∘ ξ_a
を示したことになる(ただし、Monad m
はM、Monad (t m)
はT、lift
はξで表記)。
とここまで書いて、Monad (t m) は定義に入ってないことに気がついた。return :: a -> t m a
とかを暗黙に期待しているから、別に要らないだろってことでいいのかな。