Listモナド
リストもモナドである。意外なことにリストもモナドである。
リストには要素数が0個の空リストがありうる。
これは後述するMaybe や Either における失敗の表現のようなものとも言える。
モナドだから return で値を中に入れることができる。
hoge::Int -> [Int] hoge x = return x main = do print $ hoge 5 -- [5]
モナドだから join で一皮むくことができるが、 join で裸にはできない。
import Control.Monad main = do let a = [[1,2],[3,5],[5,6]] let b = [[[1],[2]],[[3],[4]]] let c = [1] print $ join a -- [1,2,3,5,5,6] print $ join b -- [[1],[2],[3],[4]] -- print $ join c -- エラー
モナドだから fmap で中の値を関数に渡すことができる。
リストには特に map というのも用意されているが、結果は fmap と同じ。
main = do let a = [1,2,3,4,5] print $ fmap (*2) a -- [2,4,6,8,10] print $ map (*2) a -- [2,4,6,8,10]
モナドだから bind ( >>= ) で中の値を、モナドを返す関数に渡すことができる。
main = do print $ [7] >>= replicate 3 -- [7,7,7]
モナドだから do構文が使える。
hoge :: [Int] -> [Int] hoge xs = do x <- xs return $ x * 2 main = do print $ hoge [1,2,3,4,5] -- [2,4,6,8,10]
Maybeモナド
Maybeは成否を表現できる。成功なら Just 値、失敗なら Nothing。
1個か0個しか要素を持てないリストのようなものとも言える。
モナドだから return で値を中に入れることができる。
hoge::Int -> Maybe Int hoge x = return x main = do print $ hoge 5 -- Just 5
モナドだから join で一皮むくことができるが、 join で裸にはできない。
import Control.Monad main = do let a = Just(Just 5) :: Maybe (Maybe Int) let b = Just Nothing :: Maybe (Maybe Int) let c = Just 2 print $ join a -- Just 1 print $ join b -- Nothing -- print $ join c -- エラー
モナドだから fmap で中の値を関数に渡すことができる。
main = do let a = Just 5 print $ fmap (*2) a -- Just 10
モナドだから bind ( >>= ) で中の値を、モナドを返す関数に渡すことができる。
hoge :: Int -> Maybe Int hoge x | x >= 10 = Just (x `div` 10) | otherwise = Nothing main = do print $ Just 50 >>= hoge -- Just 5 print $ Just 5 >>= hoge -- Nothing
モナドだから do構文が使える。
hoge :: Maybe Int -> Maybe Int hoge mx = do x <- mx if x >= 10 then return (x `div` 10) else Nothing main = do print $ hoge (Just 50) -- Just 5 print $ hoge (Just 5) -- Nothing print $ hoge Nothing -- Nothing
失敗するかもしれない関数を連鎖できる。
途中で失敗した場合、その後の計算は行われず最終結果は失敗になる。
hoge :: Int -> Maybe Int hoge x | x >= 10 = Just (x `div` 10) | otherwise = Nothing main = do print $ Just 500 >>= hoge >>= hoge -- Just 5 print $ Just 50 >>= hoge >>= hoge -- Nothing print $ Just 5 >>= hoge >>= hoge -- Nothing
Eitherモナド
Eitherは成否を表現でき、失敗にも値(エラー情報)を持てる。成功なら Right 値、失敗なら Left 値。
Maybeの拡張してエラー情報を持てるようにしたようなものと言える。
モナドだから return で値を中に入れることができる。
hoge::Int -> Either String Int hoge x = return x main = do print $ hoge 5 -- Right 5
モナドだから join で一皮むくことができるが、 join で裸にはできない。
import Control.Monad main = do let a = Right(Right 5) :: Either String (Either String Int) let b = Right(Left "hoge") :: Either String (Either String Int) let c = Right 2 :: Either String Int print $ join a -- Right 5 print $ join b -- Left "hoge" -- print $ join c -- エラー
モナドだから fmap で中の値を関数に渡すことができる。
main = do let a = Right 5 :: Either String Int print $ fmap (*2) a -- Right 10
モナドだから bind ( >>= ) で中の値を、モナドを返す関数に渡すことができる。
hoge :: Int -> Either String Int hoge x | x >= 10 = Right (x `div` 10) | otherwise = Left "error" main = do print $ Right 50 >>= hoge -- Right 5 print $ Right 5 >>= hoge -- Left "error"
モナドだから do構文が使える。
hoge :: Either String Int -> Either String Int hoge mx = do x <- mx if x >= 10 then return (x `div` 10) else Left "error" main = do print $ hoge (Right 50) -- Right 5 print $ hoge (Right 5) -- Left "error" print $ hoge (Left "hoge") -- Left "hoge"
失敗するかもしれない関数を連鎖できる。
途中で失敗した場合、その後の計算は行われず最終結果は失敗になる。
hoge :: Int -> Either String Int hoge x | x >= 10 = Right (x `div` 10) | otherwise = Left "error" main = do print $ Right 500 >>= hoge >>= hoge -- Right 5 print $ Right 50 >>= hoge >>= hoge -- Left "error" print $ Right 5 >>= hoge >>= hoge -- Left "error"