9

のメソッドの下でどのように機能するかを実際の例で誰かが説明できscalaz.Validationますか? と. loopSuccess_loopFailure

ソースコードからの抜粋 (scalaz7):

scalaz.検証:

/** Spin in tail-position on the success value of this validation. */
def loopSuccess[EE >: E, AA >: A, X](success: AA => X \/ Validation[EE, AA], failure: EE => X): X =
Validation.loopSuccess(this, success, failure)

/** Spin in tail-position on the failure value of this validation. */
def loopFailure[EE >: E, AA >: A, X](success: AA => X, failure: EE => X \/ Validation[EE, AA]): X =
Validation.loopFailure(this, success, failure)

コンパニオン オブジェクト:

object Validation extends ValidationFunctions with ValidationInstances {

  /** Spin in tail-position on the success value of the given validation. */
  @annotation.tailrec
  final def loopSuccess[E, A, X](d: Validation[E, A], success: A => X \/ Validation[E, A], failure: E => X): X =
    d match {
      case Failure(e) => failure(e)
      case Success(a) => success(a) match {
        case -\/(x) => x
        case \/-(q) => loopSuccess(q, success, failure)
      }
    }

  /** Spin in tail-position on the failure value of the given validation. */
  @annotation.tailrec
  final def loopFailure[E, A, X](d: Validation[E, A], success: A => X, failure: E => X \/ Validation[E, A]): X =
    d match {
      case Failure(e) => failure(e) match {
        case -\/(x) => x
        case \/-(q) => loopFailure(q, success, failure)
      }
      case Success(a) => success(a)
    }

}
4

1 に答える 1

5

これはトランポリンに似ています。loopSuccess には、初期値と、次の状態に移行する関数を指定します。次の 3 つの状態が考えられます。

X.left           // stop processing with X as the result
Success(a).right // no result, run the next iteration with this value
Failure(e).right // stop processing, run the failure function on this result and return it

for loopFailure は、Failure と Success を逆にして同じことを行うため、left または Success を返すまで実行し続けます。

loopSuccess の使用例を次に示します。

import scalaz._
import Scalaz._

object TestLoopSuccess extends App {
  // check if a number divides another, returning a Failure for division by zero
  val divides : Int => Int => Validation[String,Boolean] = { div => num =>
    if(div == 0) "division by zero".failure
    else (num % div == 0).success
  }

  val allDivide : Int => List[Int] => String \/ Validation[Int,List[Int]] = { div => nums => 
    nums match {
      // empty list means we are done, so we return a left
      case Nil => "All numbers divide".left

      // process the head of the list and return a right
      case x::xs => divides(div)(x).flatMap { divides => 
        if(divides) 
          // head divides, so process more of the list
          xs.success 
        else 
          // head does not divide, so we are done
          "%d is not a multiple of %d".format(x,div).failure
      }.right
    }
  }

  println(Validation.loopSuccess(List(2,4,6,8).success[String], allDivide(0), identity[String])) // "division by zero"
  println(Validation.loopSuccess(List(2,4,6,8).success[String], allDivide(2), identity[String])) // "All numbers divide"
  println(Validation.loopSuccess(List(2,4,7,8).success[String], allDivide(2), identity[String])) // "7 is not a multiple of 2"
}
于 2012-12-28T16:50:52.370 に答える