9.4 Common Monads
このセクションではよく使われる2つのモナド、List モナドと Maybe モナドについて説明されている。リストやMaybe 型のデータはよく使われるが、これらは実はモナドでもある。 リストモナドの定義は次のようになっている。 instance Monad [] where return x = [x] l >>= concatMap f l fail _ = [] YAHT ではリストモナドの関数の定義についてはさらっと触れるだけで、応用の説明に移っているが、ここでは定義について少し考えてみる。 return 関数は引数をひとつとり、それをリストにラッピングして返す。たとえば return 1 == [1] だ。return は多相関数なので IO モナドでも同じ名前の関数が使われる。ghci で単に return 1 とすると IO 1 が返るが。 Prelude> return 1 1 次のように工夫すれば、型推定を利用して、return 1 が [1] であることを確かめることができる。 Prelude> return 1 ++ [2,3] [1,2,3] 次の定義は、bind 演算子 >>= の定義だが、最初の引数の l はリスト型のデータで、次の引数の f は引数がひとつで戻値がリストの関数 a -> [b] 型の関数であることに注意しておく必要がある。 l >>= concatMap f l 上の定義で concatMap f l は、concat $ map f l だ。つまり、ます、リスト l の要素の各々に関数 f を関数適用させたリストを作る。要素は a 型で、f :: a -> [b] は a 型の引数ひとつを取り、リスト型の値 [b] を返す関数だ。したがって、map f [a1,a2,a3] == [[b1], [b2], [b3]] となる。これに concat を関数適用すると、[b1,b2,b3] になる。これは ghci で次のように確かめることができる。 Prelude> [1,2,3] >>= (\x -> [x*2]) [2,4,6] fail 関数はどのような引数に対しても空のリスト [] を返すが、後の例には出てこないので省略する。 リストはモナドなので、次のように do 記法を利用することができる。 Prelude> :set +m Prelude> let Prelude| cross l1 l2 = do Prelude| x <- l1 Prelude| y <- l2 Prelude| return (x,y) Prelude| これはどういうプログラムなのだろうか、とりあえず使ってみて動作を見てみる。 Prelude> cross "ab" "cde" [('a','c'),('a','d'),('a','e'),('b','c'),('b','d'),('b','e')] 結果はリスト "ab" の要素とリスト "cde" の要素をひとつづつ組み合せたペアからなるリストになる。しかし、どうしてこのような値になるのだろうか。 これを解読するためには、上の do 記法をモナドの演算に書き換える必要がある。それは次のようになる。 Prelude> let cross2 l1 l2 = l1 >>= \x -> (l2 >>= \y -> return (x,y)) Prelude| Prelude> cross2 "ab" "cde" [('a','c'),('a','d'),('a','e'),('b','c'),('b','d'),('b','e')] これでも分かりやすいとは言えないので >>= 演算子を定義のとおりに書き換えてみる。 Prelude> let cross3 l1 l2 = concatMap (\x -> (concatMap (\y -> [(x,y)]) l2)) l1 Prelude| Prelude> cross3 "ab" "cde" [('a','c'),('a','d'),('a','e'),('b','c'),('b','d'),('b','e')] これなら、リスト "ab" の 'a' を x にバインドして、x = a にたいしてリスト "cde" の要素とのペアのリスト [('a','c'),('a', 'd'),('a','e)]作り、 さらに 'b' とのペアのリスト [('b','c'),('b','d'),('b','e')] を作り、それらを結合させるという動作を読み取ることができる。 上の do 記法が次のようなリストの内包的定義と似ているのは偶然ではない。 Prelude> [(x,y) | x <- "ab", y <- "cde"] [('a','c'),('a','d'),('a','e'),('b','c'),('b','d'),('b','e')] 実はリストの内包的定義は、リストモナドの do 記法の省略形なのだ。 Yet Another Haskell Tutorial 30 へ続く ...
by tnomura9
| 2013-03-14 00:30
| Haskell
|
Comments(0)
|
カテゴリ
新型コロナウイルス 主インデックス Haskell 記事リスト 圏論記事リスト 考えるということのリスト 考えるということ ラッセルのパラドックス Haskell Prelude Ocaml ボーカロイド 圏論 jQuery デモ HTML Python ツールボックス XAMPP Ruby ubuntu WordPress 脳の話 話のネタ リンク 幸福論 キリスト教 心の話 メモ 電子カルテ Dojo JavaScript C# NetWalker ed と sed HTML Raspberry Pi C 言語 命題論理 以前の記事
最新のトラックバック
最新のコメント
ファン
記事ランキング
ブログジャンル
画像一覧
|
ファン申請 |
||