MonadIOクラスのこと

昨日モナドトランスフォーマーの勉強中に使ったliftIOですが、勘違いをしていたことにやっと気がつきました。liftIOの型情報は

liftIO :: IO a -> m a

と、この関数だけ見るとIOアクションをほかのどんな形のモナドにでも挿げ替えてくれるハッキーな関数のようにしか見えなかったのですが、もうちょっと周りを見ると、実は、このliftIOはMonadIOというクラスのメソッドなんですね。そして、このクラスのインスタンス宣言のほうにも大切な情報が隠れていました。

class Monad m => MonadIO m where
	liftIO :: IO a -> m a

Instances
MonadIO IO
MonadIO m => MonadIO (ListT m)
MonadIO m => MonadIO (ContT r m)
(Error e, MonadIO m) => MonadIO (ErrorT e m)
MonadIO m => MonadIO (ReaderT r m)
MonadIO m => MonadIO (StateT s m)
MonadIO m => MonadIO (StateT s m)
(Monoid w, MonadIO m) => MonadIO (WriterT w m)
(Monoid w, MonadIO m) => MonadIO (WriterT w m)
(Monoid w, MonadIO m) => MonadIO (RWST r w s m)
(Monoid w, MonadIO m) => MonadIO (RWST r w s m)

ということで、MonadIOを継承しているモナドモナドすべてなわけでないし、型パラメタを取るインスタンス宣言もよく見ると皆Monad mではなく、MonadIO mしかとっていません。つまり、これは、昨日探していて見つけられなかったIOTのようなもので、インスタンス宣言に列挙されているモナドについて、IOとの組み合わせ方を規定しているように見えます。いずれにせよ、
liftIO :: IO a -> m a
のmはどんなモナドでもよいわけではなく、何らかの形でIOを含んだ複合モナドということのようです。だから、unsafePerformIOみたいなIOアクションをIOアクションのないところで動かすためのトリックというよりは、複合型モナドの中での型整合をとるための方策ということのようです。

ではでは