Control.Monad.Trans.Control がよくわからないのでいろいろ調べてみた。
MonadTransControl
がやりたいのは、MaybeT
とrunMaybeT
、もしくはListT
とrunListT
、のようにXxxxTとrunXxxxTの組の操作を抽象化したいということだと思われる。
例えば、MaybeT [] a
にreverse
を適用したい場合、MaybeT [] a
は[Maybe a]
のことなので、runMaybeT
でラップを外してリストを処理してからMaybeT
で再ラップすることで以下のように書ける。
reverseMaybeT :: MaybeT [] a -> MaybeT [] a
reverseMaybeT = MaybeT . reverse . runMaybeT
MonadTransControl
型クラスを使えば、reverseMaybeTを様々なモナド変換子に対して一般的に定義できる。
reverseT :: (Monad (t []), MonadTransControl t) => t [] a -> t [] a
reverseT t = liftWith (\run -> reverse $ run t) >>= restoreT . return
run
がrunMaybeT
、restoreT
がMaybeT
(コンストラクタ)、StT t
はMaybe
の役割を果たす。run t
によってラップを剥がしてリストにしてくれるのだが、その型は当然t
によって違い[StT t a]
のような型で返ってくるので、総称的にリストを操作する関数だけが利用できる。
ちなみにreverseT
の定義の末尾のreturn
が非常に気持ち悪いのだけど、これはどう解釈すればいいんだろ。型を見れば必要なのはわかるんだけど、最初のreverseMaybeT
の定義と比較すると乖離が激しくて、ちょっと気持ち悪い。
ここまでわかれば、MonadBaseControl
型クラスもMonadTransControl
とほぼ同じ物と見なせばいいと思う。MonadIO
が重要なのと同様に、MonadBaseControl
の方が用途は広い気がする。