2012年4月16日月曜日

Scala Tips / Validation (1) - 値の取り出し

ValidationはScalazが提供する成功/失敗の計算文脈を提供するモナドです。

Validationを使ってOptionやEitherと同様の成功/失敗の計算文脈上でのMonadicプログラミングをすることができます。ValidationではSuccessで成功、Failureで失敗を表現します。

Validationは、名前から分かるように入力フォームのプロパティやRESTサービスの引数といったところでのバリデーション用途を想定しており、失敗側の情報を積算していけるのが特徴となっています。

今回はValidationから値を取り出すイディオムです。

Validation[Throwable, Int]がSuccessの場合はSuccessの値(Int)を、Failureの場合は0を返す処理を考えます。

(分類の基準)

Java風

if式でValidation#isSuccessメソッドを使ってSuccessとFailureの判定をして、処理を切り分ける事ができます。ただ、asInstanceOfが必要になるので、あまり使いたくない用法です。

def f(a: Validation[Throwable, Int]): Int = {
  if (a.isSuccess) a.asInstanceOf[Success[Throwable, Int]].a else 0
}

Scala風

match式を使うとSuccessとFailureのパターンマッチングで書くことができます。

def f(a: Validation[Throwable, Int]): Int = {
  a match {
    case Success(s) => s
    case Failure(_) => 0
  }
}

Scala

ValidationはScalazの機能なので、「Scala」というのは変ですが、foldメソッドを用いるのがScala流のコーディングです。Validationのfoldメソッドは、第一引数にFailureの値を変換する関数、第二引数にSuccessの値を変換する関数を指定します。

def f(a: Validation[Throwable, Int]): Int = {
  a.fold(_ => 0, identity)
}

第一引数と第二引数はどちらも同じ値を返す関数がデフォルト値になっているので、省略することができます。今回の処理では、Successは格納されている値をそのままとり出せばよいので、第二引数を省略することができます。

def f(a: Validation[Throwable, Int]): Int = {
  a.fold(_ => 0)
}

Scalaz

Validationの「|」メソッドで、Successの場合は値の取り出し、Failureの場合は指定したデフォルト値を取り出すことができます。

def f(a: Validation[Throwable, Int]): Int = {
  a | 0
}

ノート

今回の課題は「|」メソッドがぴったりなので、これを使うのがベストです。思い浮かばなかった場合は、Scalaの常道でfoldを使うのがよいでしょう。

Scalazの他の機能で同じ処理を実現することもできます。こちらは、メリットはないので実際に使用することはないですが、バリエーションとして挙げておきます。

Validationの「|||」メソッドは、Successの場合は値の取り出し、Failureの場合は指定したFailureの値を関数で変換して取り出す関数です。ここでは、引数に必ず0を返す関数を指定して、Failureの場合は0を返すようにしてみました。

def f(a: Validation[Throwable, Int]): Int = {
  a ||| (_ => 0)
}

Validationでの使用方法が思いつかない場合は、よく慣れているOptionに変換して処理を進める方法もあります。

def f(a: Validation[Throwable, Int]): Int = {
  a.toOption | 0
}

諸元

  • Scala 2.9.2
  • Scalaz 6.0.4

今回よりScalaのバージョンを2.9.2、Scalazのバージョンを6.0.4に上げました。どちらもメンテナンスバージョンアップなので、基本的には以前の記事の環境と違いはないと思います。

0 件のコメント:

コメントを投稿