人気ブログランキング | 話題のタグを見る

Yet Another Haskell Tutorial 31

9.5 Monadic Combinators

Haskell の Control.Monad モジュールにはいろいろな monad combinator がそろっている。

• (=<<):: (a->mb)->ma->mb
• mapM:: (a->mb)->[a]->m[b]
• mapM_ :: (a->mb)->[a]->m()
• filterM:: (a->mBool)->[a]->m[a]
• foldM:: (a->b->ma)->a->[b]->ma
• sequence :: [m a] -> m [a]
• sequence_ :: [m a] -> m ()
• liftM:: (a->b)->ma->mb
• when:: Bool->m()->m()
• join:: m(ma)->ma

=<< 演算子の意味は >>= と同じだが、引数の配置が違う。そのため、return "hello, world" >>= putStrLn は、=<< を使って、putStrLn =<< return "hello, world" と書ける。

Prelude> return "hello, world" >>= putStrLn
hello, world
Prelude> putStrLn =<< return "hello, world"
hello, world

mapM と mapM_ はリストの map と同じような働きをするが、第1匹数の関数がモナドの関数である事と、結果をモナドでラッピングして返す所が異なっている。この関数はモナドでプログラムするときに非常に便利だ。

Prelude> mapM_ print [1,2,3]
1
2
3

mapM とアンダースコアのついた mapM_ の違いは、前者はモナド型の戻り値を返すが、後者は戻り値を返さないことだ。

Prelude> mapM print [1,2,3]
1
2
3
[(),(),()]
Prelude> mapM_ print [1,2,3]
1
2
3

foldM は foldl と動作が似ているが、foldM の第1引数はモナド型の値を戻す関数になる。

Prelude> :m Control.Monad
Prelude Control.Monad> foldM (\a b -> putStrLn (show a ++ "+" ++ show b ++ "=" ++ show (a+b)) >> return (a+b)) 0 [1..5]
0+1=1
1+2=3
3+3=6
6+4=10
10+5=15
15

sequence はアクションのリストを順番に実行する。

Prelude Control.Monad> sequence [print 1, print 2, print "world"]
1
2
"world"
[(),(),()]
Prelude Control.Monad> sequence_ [print 1, print 2, print "world"]
1
2
"world"

liftM 関数は2つの引数をとる。第1の引数に純粋関数をとり、それをモナド関数に変換して、第2引数のモナド値に関数適用する。これは、純粋関数をモナド値のコンテナの値に適用するのと同じ事になる。

Prelude Control.Monad> liftM (+1) (Just 5)
Just 6

応用でファイルの行に番号を打って表示するには次のようにする。

Prelude Control.Monad> :!echo "hello\nworld" > test.txt
Prelude Control.Monad> :!cat test.txt
hello
world
Prelude Control.Monad> :set +m
Prelude Control.Monad> do
Prelude Control.Monad|   l <- liftM lines (readFile "test.txt")
Prelude Control.Monad|   let n = zipWith (\n t -> show n ++ ' ' : t) [1..] l
Prelude Control.Monad|   mapM_ putStrLn n
Prelude Control.Monad|
1 hello
2 world

when は第1引数の条件が成立したときのみ、第2引数のモナド関数が実行される。

Prelude Control.Monad> mapM_ (\l -> when (not $ null l) (putStrLn l)) ["","abc","def","","","ghi"]
abc
def
ghi

join はモナドの値について concat と同じ働きをする。

Prelude Control.Monad> join (Just (Just 'a'))
Just 'a'
Prelude Control.Monad> join (Just (Nothing :: Maybe Char))
Nothing
Prelude Control.Monad> join (Nothing :: Maybe (Maybe Char))
Nothing
Prelude Control.Monad> join (return (putStrLn "hello"))
hello
Prelude Control.Monad> return (putStrLn "hello")
Prelude Control.Monad> join [[1,2,3],[4,5]]
[1,2,3,4,5]

Yet Another Haskell Tutorial 32 へ続く
by tnomura9 | 2013-03-17 01:45 | ツールボックス | Comments(0)
<< Yet Another Has... Yet Another Has... >>