2012年8月1日水曜日

クラウド温泉3.0 (11) / reduce, collect, flatMap

クラウド温泉3.0@小樽のセッション「Monadicプログラミング・マニアックス」で使用するスライドのネタ検討その11です。

前回はFunctorが提供する計算文脈におけるパイプラインで使用できるmapメソッド、filterメソッド、foldメソッドを取り上げました。この3つが基本中の基本になりますが、他にも有用なものがあります。

reduce

reduceメソッドはコンテナ内の要素に対して二項演算を繰り返し適用し、ひとつの要素にまとめる処理を行います。foldメソッドの用途限定版です。

scala> List(1, 2, 3).reduce(_ + _)
res2: Int = 6

collect

collectメソッドは部分関数(partial function)を使って、要素の選択を変換を同時に行います。filterメソッドとmapメソッドを一つにまとめたような動きになります。

scala> List(1, 2, 3).collect {
     |  case x if x % 2 == 1 => x.toString
     | }
res5: List[java.lang.String] = List(1, 3)

flatMap

flatMapメソッドはモナドの動作を行うメソッドです。mapメソッドに指定する関数が要素の変換を行うのに対して、flatMapメソッドに指定する関数は要素からコンテナへの変換を行います。このコンテナの集まりを"コンテナの流儀"でひとつのコンテナにまとめるのがモナドの肝となる動きになります。

scala> List(1, 2, 3).flatMap(x => {
     | if (x % 2 == 1) List(x.toString, (x * 10).toString) else Nil
     | })
res7: List[java.lang.String] = List(1, 10, 3, 30)

Listの場合は、Listの集まりを順序を維持したまま一つのListにまとめます。このため、flatMapの実行でListの要素数を増やしたり減らしたりといったことが可能です。上記の例では、リストの要素数が3から4に増えています。

パイプラインの構成部品

パイプラインの構成部品の表にreduce, collect, flatMapを追加しました。

メソッド動作動作イメージコンテナ型要素型要素数
mapコンテナ内の要素に関数を適用して新しいコンテナに詰め直す。M[A]→M[B]変わらない変わる変わらない
filterコンテナ内の要素を選別して新しコンテナに詰め直す。M[A]→M[A]変わらない変わらない減る
foldコンテナをまるごと別のオブジェクトに変換する。M[A]→N変わる--
reduceコンテナの内容を一つにまとめる。M[A]→A変わる--
collectコンテナ内の要素に部分関数を適用して選択と変換を行う。M[A]→M[B]変わらない変わる減る
flatMapコンテナ内の要素ごとにコンテナを作成する関数を適用し最後に一つのコンテナにまとめる。M[A]→M[B]変わらない変わる増える/減る |

メソッドの追加に加えて、以下の点を変更しています。

  • コンテナ→コンテナ型、要素→要素型
  • コンテナ型が「変わる」の時は要素型、要素数は意味を持たないので「-」とした。

パイプラインで有用な部品のパターンは概ねカバーできたと思います。

ノート

スライド的には、この表で一つスライドを起こして、各メソッドを例題付きで簡単に説明する感じになりそうです。

foldとreduce

reduceはfoldの特殊な形なのでfoldファミリと考えるとよいでしょう。fold系の処理の中で条件によってreduceを選ぶという形になります。

foldファミリは、Monoidと相性が良いので、Monoidとどう組合せていくのかというのも重要な論点になります。これはMonoidで一つスライドを起こして説明したいと思います。

foldMap

flatMapメソッドは、まさにMonadicプログラミングの核となるメソッドです。

この比較表ではflatMapメソッドの威力はあまり見えてきません。これはFunctor視点の比較表になるためですね。flatMapについては別枠で説明することにすることになります。

0 件のコメント:

コメントを投稿