readhbon.doorkeeper.jp
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
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
パターンマッチが使える
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式を使わずにパターンマッチしないパターンマッチを使うとエラーになる。
wopwop :: Maybe Char
wopwop = do
(x:xs) <- Just ""
return x
main = do
print $ Just "Hello" >>= \(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"]
文脈は非決定性
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)