lifted applicative style
モナドを使った演算を書いている時は、applicative styleを使うと記述量を少なくできて便利だ。
>>> (++) <$> getLine <*> getLine hoge foobar "hogefoobar"
使う関数が最終的にモナドを返す場合、最後にjoinしてやればいい。
>>> let catPut a b = putStrLn ("== " ++ a ++ b) >>> join $ catPut <$> getLine <*> getLine hoge foobar == hogefoobar
さて、上記と同様のことをmonad transformerで拡張した文脈中ではどうするか、ちょっと悩んでしまった。
正解は(lift =<<)を使えばいい。
>>> let action = lift =<< catPut <$> ask <*> lift getLine >>> runReaderT action "hoge" foobar == hogefoobar
(lift =<<)の型はこうだ。
>>> :t (lift =<<) (lift =<<) :: (Monad (t m), Monad m, MonadTrans t) => t m (m b) -> t m b
見ての通り、join :: Monad m => m (m b) -> m b によく似ている。
ちなみにcatPutへの引数がモナドではない素のデータだとこうなる。
>>> let action' = lift $ catPut "HOGE" "FOOBAR" :: ReaderT String IO () >>> runReaderT action' "hoge" == HOGEFOOBAR
素のデータの場合の記法から、($)を(=<<)に、関数適用を(<$>)と(<*>)に書き換えればapplicative styleになる。