Reader モナドは引数隠蔽モナド
以前にもエントリを書きましたが、Readerモナドがさっぱり分からないので、もう一度勉強してみました。
あまり深く考えずに Reader a を a -> と読み替えると、関数の型は以下のようになります。
関数 | 型 | 等価な関数 |
---|---|---|
(>>=) | (a->b) -> (b->a->c) -> a -> c | |
(=<<) | (a->b->c) -> (b->a) -> b -> c | |
(>>) | (a->b) -> (a->c) -> a -> c | flip const |
return | a -> b -> a | const |
ap | (a->b->c) -> (a->b) -> a -> c | <*> |
liftM | (a->b) -> (c->a) -> c -> b | (.) |
ask | a -> a | id |
local | (a->a) -> (a->b) -> a -> b | flip (.) |
ちょっと確かめてみると、確かに等価であることが分かります。
Prelude Control.Monad.Reader> (+3)`liftM`(*3) $ 2 9 Prelude Control.Monad.Reader> return 5 3 5 Prelude Control.Monad.Reader> ask 4 4
つまり Reader モナドは引数隠蔽モナドだと思えばいいわけですね。本当は第一引数があるのだけれども、あたかもそれが引数に存在しないかのように記述できると。
ということは、Reader モナドを使って書いた↓の simpleR、modifyR は simple、modify みたいに書いても同じことだ。
僕にはこの方が分かりやすいな。引数を引き回したくない気持ちは確かに分からないでもないけど、そのためにモナドの枠組みで do とか書かなきゃいけないのは、ちょっと面倒な気がする。
import Control.Monad.Reader env :: [Int] env = [1,2,3] simpleR :: Reader [Int] Int simpleR = return head =<< ask modifyR :: Reader [Int] Int modifyR = local tail simpleR simple :: [Int] -> Int simple = head modify :: [Int] -> Int modify = simple . tail main :: IO () main = do print $ runReader simpleR env print $ runReader modifyR env print $ simple env print $ modify env