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

便利な Applicative

Applicative について少し調べてみたがよく分からなかった。しかし、pure, <$>, <*> などを例示に従って使ってみると結構便利なものだと感じた。これらは、Prelude 単体でも使える。理屈はどうでもいいのでとにかく使ってみた。

Maybe モナドの Just 2 のコンテナの中身に (+10) を施したい時はよくあるだろう。モナドでこれを実現しようと思ったら次のようになる。

Prelude> Just 2 >>= \x -> return (x + 10)
Just 12

これを Applicative の演算子 <$> を使うと次のように書ける。

Prelude> (+10) <$> Just 2
Just 12

これは Haskell の $ 演算子の使い方とそっくりだ。

Prelude> (+10) $ 2
12

モナドのデータを使っているときは、これだけでも Applicative の演算子 <$> を使いたくなる理由になる。しかしこれに <*> 演算子を組み合わせるともっと便利だ。<*> を使えば、最初の関数が 2 引数関数でも計算できるのだ。

Prelude> (+) <$> Just 1 <*> Just 2
Just 3

これはモナドでないデータを Haskell で計算するときのやり方とそっくりだ。

Prelude> (+) 1 2
3

しかし、Haskell の $ 演算子を使って同じようなことをすると、次のように余分な括弧が必要だ。

Prelude> ((+) $ 1) $ 2
3

これをモナドで計算しようとすると次のように大変なことになる。

Prelude> Just 1 >>= \x -> (Just 2 >>= \y -> return (x + y))
Just 3

こうなってくるとモナドのコンテナの中身を計算するときは Applicative の演算子以外は使いたくなくなる。

次に pure 関数だが、これは引数の関数をモナドの値同士の関数に使えるように格上げするという働きがある。例えば、(+) 関数はモナドではない値の演算で次のように演算できるが、

Prelude> (+) 1 2
3

この演算子を Just 1 と Just 2 に使いたいときは、pure (+) を使えば良い。具体的には次のようになる。

Prelude> pure (+) <*> Just 1 <*> Just 2
Just 3

明らかに pure (+) <*> を使った演算と、(+) <$> の演算は同じ結果になる。

Prelude> (+) <$> Just 1 <*> Just 2
Just 3

Prelude で使える Applicative の演算子はこのほかにも *> と <* があるが、これは演算子の左右の値のどちらかを選択するという意味がある。

Prelude> Just 1 *> Just 2
Just 2
Prelude> Just 1 <* Just 2
Just 1

リストも Apllicative のインスタンスなので、次のような芸当もできる。

Prelude> (*2) <$> [1,2,3]
[2,4,6]

Applicative の概念はプログラム言語のパーサの開発から発生したものらしく、パーサーを記述するときにその効力がいかんなく発揮されるらしい。例えば、Parsec 3 には Applicative が採用されている。

しかし、Applicative とは何かというような難しいことは置いておいて、モナドのコンテナの値を加工するのに便利な演算子があるという捉え方から、Applicative にアプローチしても良いような気がする。

追記

Applicative についてはブログ『あどけない話』の『Applicative のススメ』が分かりやすかった。

by tnomura9 | 2016-10-15 06:30 | Haskell | Comments(0)
<< Data.Tree で遊ぶ ディレクトリーツリーの取得 >>