Readerモナド
Readerモナドは、読み取り専用のStateモナドのようなものである。
Stateモナドはグローバル変数のようなものとして利用できたが、
Readerモナドはグローバル定数のようなものとして利用できる。
Stateモナドでは状態の取得にgetを用いたが、Readerモナドでは ask を用いる。
Stateモナドの runState に相当するのは runReader だが、状態は変化しないので値のみ返す。
import Control.Monad.Reader calcTax :: Int -> Reader Int Int calcTax x = do tax <- ask let y = (x * (100 + tax)) `div` 100 return y main :: IO () main = do print $ (`runReader` 8) $ do a <- calcTax 100 b <- calcTax 500 c <- calcTax 1000 return (a, b, c) -- (108,540,1080) print $ (`runReader` 10) $ do a <- calcTax 100 b <- calcTax 500 c <- calcTax 1000 return (a, b, c) -- (110,550,1100)
モナドだから return で値を中に入れることができる。
import Control.Monad.Reader hoge :: Int -> Reader String Int -- 状態: String, 値: Int hoge x = return x main :: IO () main = do let ma = hoge 5 let a = runReader ma "hoge" print a -- 5 ※ Stateとは異なり、状態は返さない
モナドだから join で一皮むくことができるが、 join で裸にはできない。
import Control.Monad import Control.Monad.Reader hoge :: Int -> Reader s Int hoge x = return x main :: IO () main = do let ma = hoge 5 :: Reader String Int let mma = return ma :: Reader String (Reader String Int) let ma' = join mma -- Reader String Int -- let a' = join ma' -- エラー let a' = runReader ma' "hoge" print a' -- 5
モナドだから fmap で中の値を関数に渡すことができる。
import Control.Monad.Reader hoge :: Int -> Reader String Int hoge x = return x main :: IO () main = do let ma = hoge 5 :: Reader String Int let mb = fmap (*2) ma let b = runReader mb "hoge" print b -- 10
モナドだから bind ( >>= ) で中の値を、モナドを返す関数に渡すことができる。
import Control.Monad.Reader hoge :: Int -> Reader String Int hoge x = return (x * 2) main :: IO () main = do let ma = hoge 5 let mb = ma >>= hoge let a = runReader ma "hoge" let b = runReader mb "piyo" print a -- 10 print b -- 20
またすでに見た通り、モナドだから do構文が使える。
Writerモナド
Writerモナドは、追記専用のStateモナドのようなものである。
値の更新ではなく追記であることに注意。主にリストに追加して使う。
ログを取るために使われることが多い。
Stateモナドでは状態の更新に put / modify を用いたが、Writerモナドでは tell を用いる。
Stateモナドの runState, execState に相当するのは runWriter, execWriter である。
import Control.Monad.Writer main :: IO () main = do let s = execWriter $ do tell "hoge\n" tell "piyo\n" tell "huga\n" return () putStrLn s
モナドだから return で値を中に入れることができる。
import Control.Monad.Writer hoge :: Int -> Writer String Int -- 状態: String, 値: Int hoge x = return x main :: IO () main = do let ma = hoge 5 let a = runWriter ma -- 初期値が無いことに注意 print a -- (5,"")
モナドだから join で一皮むくことができるが、 join で裸にはできない。
import Control.Monad import Control.Monad.Writer hoge :: Int -> Writer String Int hoge x = return x main :: IO () main = do let ma = hoge 5 :: Writer String Int let mma = return ma :: Writer String (Writer String Int) let ma' = join mma -- Writer String Int -- let a' = join ma' -- エラー let a' = runWriter ma' print a' -- (5,"")
モナドだから fmap で中の値を関数に渡すことができる。
import Control.Monad.Writer hoge :: Int -> Writer String Int hoge x = return x main :: IO () main = do let ma = hoge 5 :: Writer String Int let mb = fmap (*2) ma let b = runWriter mb print b -- (10,"")
モナドだから bind ( >>= ) で中の値を、モナドを返す関数に渡すことができる。
import Control.Monad.Writer hoge :: Int -> Writer String Int hoge x = return (x * 2) main :: IO () main = do let ma = hoge 5 let mb = ma >>= hoge let a = runWriter ma let b = runWriter mb print a -- (10,"") print b -- (20,"")
またすでに見た通り、モナドだから do構文が使える。