do記法
doを使うパターンと使わないパターンで比べてみる。
type Birds = Int type Pole = (Birds, Birds) -- 鳥 landLeft :: Birds -> Pole -> Maybe Pole landLeft n (left, right) | abs ((left + n) - right) < 4 = Just (left + n, right) | otherwise = Nothing landRight :: Birds -> Pole -> Maybe Pole landRight n (left, right) | abs (left - (right + n)) < 4 = Just (left, right + n) | otherwise = Nothing routine :: Maybe Pole routine = do start <- return (0, 0) first <- landLeft 2 start second <- landRight 2 first landLeft 1 second -- doを使わないと、こんな感じで超だるい -- routine :: Maybe Pole -- routine = case landLeft 1 (0, 0) of -- Nothing -> Nothing -- Just pole1 -> case landRight 4 pole1 of -- Nothing -> Nothing -- Just pole2 -> case landLeft 2 pole2 of -- Nothing -> Nothing -- Just pole3 -> landLeft 1 pole3 main = do print $ landLeft 2 (0, 0) print $ landLeft 1 (1, 2) print $ landRight (-1) (1, 2) print $ landRight 10 (0, 3) print $ landRight 1 (0, 0) >>= landLeft 2 print $ routine
途中でバナナ
type Birds = Int type Pole = (Birds, Birds) -- 鳥 landLeft :: Birds -> Pole -> Maybe Pole landLeft n (left, right) | abs ((left + n) - right) < 4 = Just (left + n, right) | otherwise = Nothing landRight :: Birds -> Pole -> Maybe Pole landRight n (left, right) | abs (left - (right + n)) < 4 = Just (left, right + n) | otherwise = Nothing -- 途中でバナナを踏ませる routine :: Maybe Pole routine = do start <- return (0, 0) first <- landLeft 2 start Nothing second <- landRight 2 first landLeft 1 second main = do print $ routine -- Nothing
パターンマッチが使える
doの中でパターンマッチが使える。
justH :: Maybe Char justH = do (x:xs) <- Just "hello" return x main = do print $ justH
これが失敗するパターンはどうなるのか。
wopwop :: Maybe Char wopwop = do (x:xs) <- Just "" return x main = do print $ wopwop
do式の中でパターンマッチが失敗した場合、 Monad 型クラスの一員であるfail 関数が使われるとのこと。do式を使わずにパターンマッチしないパターンマッチを使うとエラーになる。
-- do 式の中でパターンマッチが失敗した場合、 Monad 型クラスの一員であるfail 関数が使われる wopwop :: Maybe Char wopwop = do (x:xs) <- Just "" return x main = do print $ Just "Hello" >>= \(x:xs) -> Just x -- Non-exhaustive patterns in lambda -- failのデフォルト実装だと死ぬ -- print $ Just "" >>= \(x:xs) -> Just x print $ wopwop
リストモナド
リストをアプリカティブ・スタイルで使うと、非決定性を表現している
main = do print $ (*) <$> [1,2,3] <*> [10,100,1000]
main = do print $ (*) <$> [1,2,3] <*> [10,100,1000] print $ [3,4,5] >>= \x -> [x,-x] print $ [] >>= \x -> ["bad", "mad", "rad"] -- [1,2,3] >>= \x -> []
文脈は非決定性
listOfTuples :: [(Int, Char)] listOfTuples = do n <- [1,2] ch <- ['a','b'] return (n, ch) main = do print $ listOfTuples
do記法とリスト内包表記
-- リスト内包表記はリストモナドの構文糖衣にすぎない main = do print $ [ (n, ch) | n <- [1,2], ch <- ['a','b'] ]
MonadPlusとガード
モノイドの性質を併せ持つのがモナドプラス。
class Monad m => MonadPlus m where mzero :: m a mplus :: m a -> m a -> m a
guard関数
guard :: (MonadPlus m) => Bool -> m () guard True = return () guard False = mzero
main = do print $ [ x | x <- [1..50], '7' `elem` show x ]
Prelude Control.Monad> guard (5 > 2) :: Maybe () Just () Prelude Control.Monad> guard (1 > 2) :: Maybe () Nothing Prelude Control.Monad> guard (5 > 2) :: [()] [()] Prelude Control.Monad> guard (1 > 2) :: [()] []
騎士の旅
import Control.Monad type KnightPos = (Int, Int) moveKnight :: KnightPos -> [KnightPos] moveKnight (c,r) = do (c', r') <- [(c+2,r-1),(c+2,r+1),(c-2,r-1),(c-2,r+1) ,(c+1,r-2),(c+1,r+2),(c-1,r-2),(c-1,r+2) ] guard (c' `elem` [1..8] && r' `elem` [1..8]) return (c', r') in3 :: KnightPos -> [KnightPos] in3 start = do first <- moveKnight start second <- moveKnight first moveKnight second canReachIn3 :: KnightPos -> KnightPos -> Bool canReachIn3 start end = end `elem` in3 start main = do print $ moveKnight (6,2) print $ moveKnight (8,1) print $ (6, 2) `canReachIn3` (6, 1) print $ (6, 2) `canReachIn3` (7, 3)
- 作者: Miran Lipovača,田中英行,村主崇行
- 出版社/メーカー: オーム社
- 発売日: 2012/05/23
- メディア: 単行本(ソフトカバー)
- 購入: 25人 クリック: 580回
- この商品を含むブログ (69件) を見る