-- どうやら IO 方面からモナドの意味を勉強するのは無謀だと分かったので、 -- Haskell のオブジェクトの中で一番なじみやすいリストを使ってモナドの -- 勉強をする。 -- -- hugs で実行する方法(これを Monad.hs として保存した場合) -- $ hugs -- > :load Monad -- > evenNums2 [1 .. 10] -- >>= 演算子はリストでは concatMap の引数をひっくり返した物らしい。 -- concatMap の型は、concatMap :: (a -> [b]) -> [a] -> [b] 。つまり、 -- 引数が関数とリスト。値がリスト。引数の関数は引数を一つ取りリストを -- 返す(ややこしい???)ここでは、偶数と奇数を判別する単純な関数を使う。 -- concatMap に渡す関数。偶数の時は [数字]、奇数の時は [] を返す -- > evenNum 2 -- 答え [2] evenNum :: Integer -> [Integer] evenNum x = if even x then [x] else [] -- 偶数の数字だけ取り分ける -- concatMap とは、リストの要素のそれぞれにある関数を適用して、 -- その答えであるリストを一まとめにして返すという物。 -- > evenNums [1 .. 10] -- 答え [2,4,6,8,10] evenNums :: [Integer] -> [Integer] evenNums list = concatMap evenNum list -- モナド演算子を使った書き方。 -- > evenNums1 [1 .. 10] -- 答え [2,4,6,8,10] evenNums1 list = list >>= evenNum -- 式を展開して書いてみる。 -- > evenNums2 [1 .. 10] -- 答え [2,4,6,8,10] evenNums2 list = list >>= (\x -> if even x then [x] else []) -- do を使った書き方 -- > evenNums3 [1 .. 10] -- 答え [2,4,6,8,10] evenNums3 list = do x <- list if even x then [x] else [] -- ここで、リストにおける return は \x -> [x] な事の確認 -- > return 2 :: [Integer] -- モナド則その1を確認しよう。 -- (return x) >>= f == f x -- つまり要素をリストに入れてまたばらして関数を適用するわけで、 -- 結局モナドしないのと一緒の事になる。 mona1 = return 10 >>= evenNum -- 答え [10] -- モナド則その2を確認しよう。 -- m >>= return == m -- あるリストをばらしてもう一度リストを作るわけで、これも何もしないのと一緒 mona2 = [1 .. 10] >>= return -- 答え [1,2,3,4,5,6,7,8,9,10] -- モナド則その3の前に、もう一つ関数を作る。 -- 5 以下の数だったら数字のリストを返し、それ以外は空。 upToFive x = if x <= 5 then [x] else [] -- ではモナド則その3。 -- (m >>= f) >>= g == m >>= (\x -> f x >>= g) -- この例では、左辺の式は、リストから偶数を抜き出し、さらにそこから5以 -- 下を抜き出す。右辺の式は、まず偶数で5以下を抜き出す関数を作成し、そ -- れにリストを適用する。 mona3a = ([1 .. 10] >>= evenNum) >>= upToFive -- 答え [2,4] mona3b = [1 .. 10] >>= (\x -> evenNum x >>= upToFive) -- 答え [2,4] -- 結論。何となくやりたい事は分かるけど、モナド則にどんな利点があるの -- かいまいち分からない。最適化に使うのだろうか。。。 -- -- 参考 : http://itpro.nikkeibp.co.jp/article/COLUMN/20061005/249933/