2012年9月26日水曜日

Scala Tips / Scala 2.10味見(14) - Try(6) 終了方法

Scala 2.10味見(12) - Try(4) 基本フォーム」で説明した通り、Tryを使った処理は以下の4種類の終了方法が考えられます。

  • 副作用のある処理を行なって完了
  • Tryのまま返す
  • 値を返す
  • 値を返すか例外を投げる

副作用のある処理を行なって終了

前回に使った例題は、「副作用のある処理を行なって終了」のカテゴリになります。

def f(a: Int, b: Int) {
  def divAB = a / b
  def plus1(x: Int) = x + 1
  def minus100DivB(x: Int) = Try(x / (b - 1))

  Try(divAB).map(plus1).flatMap(minus100DivB) match {
    case Success(v) => println(v)
    case Failure(e) => println(e)
  }
}

match式を使ってSuccessとFailureを切り分け、それぞれの処理を記述します。

Tryのまま返す

Tryのモナドを性質を活用することを考えると、できるだけTryをそのまま返すのが基本形になります。

def f(a: Int, b: Int): Try[Int] = {
  def divAB = a / b
  def plus1(x: Int) = x + 1
  def minus100DivB(x: Int) = Try(x / (b - 1))

  Try(divAB).map(plus1).flatMap(minus100DivB)
}

この関数の呼び出し側は、異常状態に対して何らかの処理を行うタイミングで、Tryに対して「副作用のある処理を行なって終了」といった具体的な処理を行います。

値を返す

正常状態でも異常状態でも、何らかの結果を返すケースもあります。

def f(a: Int, b: Int): Int = {
  def divAB = a / b
  def plus1(x: Int) = x + 1
  def minus100DivB(x: Int) = Try(x / (b - 1))

  Try(divAB).map(plus1).flatMap(minus100DivB).getOrElse(-1)
}

正常系の値はそのまま返すとして、問題は例外発生時の異常系です。

ここでは、Optionでもよく使うgetOrElseメソッドを使ってみました。

値を返すか例外を投げる

関数型プログラミングとしてはちょっと先祖返りの感もありますが、場合によっては処理の終わりに例外を投げるケースもあるでしょう。

@throws(classOf[ArithmeticException])
def f(a: Int, b: Int): Int = {
  def divAB = a / b
  def plus1(x: Int) = x + 1
  def minus100DivB(x: Int) = Try(x / (b - 1))

  Try(divAB).map(plus1).flatMap(minus100DivB) match {
    case Success(v) => v
    case Failure(e) => throw e
  }
}

Tryでこのケースのための機能はないようなので、match式を用いてSuccessとFailureを判定し、Failureの時に例外をthrowします。

ノート

プログラムの全体構造は途中はすべてTryのまま返していって、最後に副作用のある処理を行なって終了、がひとつの形です。

以下の図はオブジェクト指向プログラミングと関数型プログラミングの接続方法を説明したものですが、この図の右側・関数型プログラミングではTryモナドの計算文脈で計算を行い、左側・オブジェクト指向プログラミングに返ってきた後に副作用のある処理(本ブログの例ではprintln関数によるコンソール出力)を行うのが、Tryを使う時の基本的な考え方として有効ではないかと思います。

諸元

  • Scala 2.10.0-M7

0 件のコメント:

コメントを投稿