クラウド温泉3.0@小樽のセッション「Monadicプログラミング・マニアックス」で使用するスライドのネタ検討その9です。
前回はListを素材にパイプラインの重要な構成要素であるFunctorを取り上げました。
List処理でのmapメソッドは関数型プログラミングの定番中の定番なので、List操作あるいはコレクション操作でのmapメソッドの効用はよく知られていると思います。しかし、mapメソッドをFunctorの観点からみると、「計算文脈」というもっと重要な概念が隠れています。
Option
JavaからScalaに入った当初はOptionはnullの問題を回避するためのオブジェクトで"要素数1の劣化版コレクション"というようなイメージを持つかもしれません。Optionは格納する要素数が1つなので、Listでは有用であったmapメソッドがあってもあまりメリットがあるように感じないでしょう。そもそも存在に気づかないかもしれません。
Optionは「nullの問題を回避するためのオブジェクト」というような脇役の存在ではなく、Monadicプログラミングの花形オブジェクトの一つです。それは、Optionが「計算文脈」を提供するからです。
前回のListの例をOptionに置き換えたものは以下になります。要素数が1なのであまり面白みがありません。
scala> Some(1).map(_ * 3).map(_ + 5) res7: Option[Int] = Some(8) scala> Some(1).map(mul3).map(plus5) res8: Option[Int] = Some(8) scala> Some(1).map(mul(3, _)).map(plus(5, _)) res9: Option[Int] = Some(8) scala> Some(1).map(mulc(3)).map(plusc(5)) res10: Option[Int] = Some(8)
ところがOptionがNoneだった場合は話が変わります。OptionがNoneの場合にはmapメソッドで指定した計算がなんであっても答えは必ずNoneになります。
scala> none[Int].map(_ * 3).map(_ + 5) res14: Option[Int] = None scala> none[Int].map(mul3).map(plus5) res15: Option[Int] = None scala> none[Int].map(mul(3, _)).map(plus(5, _)) res16: Option[Int] = None scala> none[Int].map(mulc(3)).map(plusc(5)) res17: Option[Int] = None
Optionを「成功と失敗」の計算文脈と考えると、この挙動の意味が分かってきます。OptionがSomeの間はOptionの計算文脈は「成功」でmapメソッドによる計算結果は計算文脈上つまりOption上に残ります。一方、OptionがNoneになるとOptionの計算文脈は「失敗」でmapメソッドによる計算結果は必ずNoneつまり「失敗」になります。
Optionの計算文脈に関する議論は以下の記事が参考になると思います。
その他の計算文脈
また、EitherやValidationの計算文脈としての意味、使用方法は以下の記事が参考になると思います。
計算文脈
計算文脈の観点からパイプライン演算やデータフローを理解するには以下の記事が参考になると思います。
この記事は「Object-Functional Analysis and Design: 次世代モデリングパラダイムへの道標」の一環で、最後のまとめは「Object-Functional Analysis and Designまとめのまとめ」に、続編は「Object-Functional Analysis and Designふたたび」なります。
あくまで私案ですが、ソフトウェア開発方法論におけるデータフロー、パイプライン演算、計算文脈、モナド(ここまでの記事には出てきていませんが)の位置付けを考える上でのヒントになると思います。
ノート
Monadicプログラミングの重要な概念である計算文脈は説明が難しいので、スライドでどうしていくのか要検討という感じです。このあたりはプログラムをたくさん書いて体で覚えていくしかないかもしれません。スライドでは簡単な説明をした後、参考リンクを紹介という形になりそうです。
0 件のコメント:
コメントを投稿