2012年8月7日火曜日

クラウド温泉3.0 (15) / Arrow

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

今回のテーマはArrowです。Arrowは圏論の射(arrow, morphism)を型クラス化したもので、圏(category)を型クラス化したCategoryと組合せて圏論的な操作ができると思われますが、具体的なユースケースはボクもよくわかりません。

しかし、引数1の関数であるFunction1を合成するという用途では一定の利用価値があります。

Scalazでの型クラスは定義は以下のような形になります。

関数の合成

まず3倍する関数mul3と5を加える関数plus5を定義します。

scala> val mul3 = (_: Int) * 3
mul3: Int => Int = <function1>

scala> val plus5 = (_: Int) + 5
plus5: Int => Int = <function1>

Scala純正のcomposeメソッドで合成することができます。

scala> val p5m3 = mul3 compose plus5
p5m3: Int => Int = <function1>

scala> p5m3(3)
res147: Int = 24

Scala純正のandThenメソッドで合成することもできます。andThenメソッドの方が左側の関数→右側の関数の順に関数が実行されるので、よりパイプライン的です。ただandThenというメソッド名が少し重たい感じです。

scala> val p5m3 = plus5 andThen mul3
p5m3: Int => Int = <function1>

scala> p5m3(3)
res147: Int = 24

ScalazのArrowを使うと関数合成を以下のように>>>演算子で記述することができます。

scala> val p5m3 = plus5 >>> mul3
p5m3: Int => Int = <function1>

scala> p5m3(3)
res147: Int = 24

パイプライン演算子|>と組み合わせると以下のようになります。まさにパイプライン処理という感じですね。

scala> 3 |> plus5 >>> mul3
res150: Int = 24

パイプラインの複線化

&&&演算子でパイプラインを複線化、***演算子でパイプラインの並行実行を行うことができます。また、firstメソッドで一番目のパイプラインのみの実行、secondメソッドで二番目のパイプラインのみの実行を行うこともできます。

scala> 3 |> (plus5 &&& mul3)
res43: (Int, Int) = (8,9)

scala> 3 |> (plus5 &&& mul3) >>> (plus5 *** mul3)
res44: (Int, Int) = (13,27)

scala> 3 |> (plus5 &&& mul3) >>> (plus5 *** mul3) >>> mul3.first
res45: (Int, Int) = (39,27)

詳しくは「関数型とデータフロー(2)」を参照してください。

Monadicプログラミング

本セッションではMonadicプログラミングは以下のものを指すことにしました。

  • Monadを中心としつつも、旧来からあるFunctorによるプログラミング、関数合成、コンビネータなども包含しつつ、パイプライン・プログラミングのスタイルとしてまとめたもの。

Arrowによる関数合成も「パイプライン・プログラミング」であるMonadicプログラミングの重要な構成要素になります。

0 件のコメント:

コメントを投稿