2012-11-19 33 views
9

有人可以用現實世界的例子來解釋如何在scalaz.Validation的方法下工作嗎?我的意思是loopSuccessloopFailure。從源代碼(scalaz7)工作方式scalaz.Validation循環成功與循環失敗

Snippetes:

scalaz.Validation:

/** 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) 
    } 

} 

回答

5

這類似於一個trampoline。對於loopSuccess,您提供了一個初始值,以及一個將您帶到下一個狀態的函數。有三種可能的下一狀態:

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 

對於loopFailure做同樣的事情失敗和成功逆轉,讓你繼續運行,直到返回左或成功。

下面是使用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" 
}