## 动力学知识库

scalaz还提供了个type class叫Validation。乍看起来跟\/没什么分别。实际上这个Validation是在\/的基础上增加了Applicative功能，就是实现了ap函数。通过Applicative实例就可以同时运算多个Validation并返回多条异常信息。所以，\/与Validation核心分别就在于Validation可以返回多条异常信息。Validation也是由两种状态组成：Success和Failure，分别与\/的left和right相对应。Failure可以返回多个值。我们先来看看Validation在scalaz里的定义：scalaz/Validation.scala

`sealed abstract class Validation[+E, +A] extends Product with Serializable {...def isSuccess: Boolean = this match {case Success(_) => truecase Failure(_) => false}/** Return `true` if this validation is failure. */def isFailure: Boolean = !isSuccess.../** Return the success value of this validation or the given default if failure. Alias for `|` */def getOrElse[AA >: A](x: => AA): AA =this match {case Failure(_) => xcase Success(a) => a}/** Return the success value of this validation or the given default if failure. Alias for `getOrElse` */def |[AA >: A](x: => AA): AA =getOrElse(x)/** Return the success value of this validation or run the given function on the failure. */def valueOr[AA >: A](x: E => AA): AA =this match {case Failure(a) => x(a)case Success(b) => b}/** Return this if it is a success, otherwise, return the given value. Alias for `|||` */def orElse[EE >: E, AA >: A](x: => Validation[EE, AA]): Validation[EE, AA] =this match {case Failure(_) => xcase Success(_) => this}/** Return this if it is a success, otherwise, return the given value. Alias for `orElse` */def |||[EE >: E, AA >: A](x: => Validation[EE, AA]): Validation[EE, AA] =orElse(x)...`

`/** Flip the failure/success values in this validation. Alias for `unary_~` */def swap: Validation[A, E] =this match {case Failure(a) => Success(a)case Success(b) => Failure(b)}Success(3).getOrElse(0) //> res5: Int = 3Success("Three").getOrElse("Everything OK!") //> res6: String = ThreeFailure("Something wrong!").swap.getOrElse("Everything OK!")//> res7: String = Something wrong!(~Failure("Something wrong!")).getOrElse("Everything OK!")//> res8: String = Something wrong!`

Validation的两个状态是这样定义的：

`final case class Success[A](a: A) extends Validation[Nothing, A]final case class Failure[E](e: E) extends Validation[E, Nothing]`

` 1 for { 2 a <- Success(3) 3 b <- Success(2) 4 } yield a + b //> res5: scalaz.Validation[Nothing,Int] = Success(5) 5 6 val valid= for { 7 a <- Success(3) 8 c <- Failure("oh, error!"): Validation[String,Int] 9 d <- Failure("oh, error again!"): Validation[String,Int]10 b <- Success(2)11 } yield a + b //> valid : scalaz.Validation[String,Int] = Failure(oh, error!)12 if (valid.isFailure) valid.swap.getOrElse("no error")13 //> res6: Any = oh, error!`

scalaz同样为所有类型值提供了注入方法：scalaz.syntax/ValidationOps.scala

`final class ValidationOps[A](self: A) {def success[X]: Validation[X, A] = Validation.success[X, A](self)def successNel[X]: ValidationNel[X, A] = successdef failure[X]: Validation[A, X] = Validation.failure[A, X](self)@deprecated("use `failure` instead", "7.1")def fail[X]: Validation[A, X] = failure[X]def failureNel[X]: ValidationNel[A, X] = Validation.failureNel[A, X](self)@deprecated("use `failureNel` instead", "7.1")def failNel[X]: ValidationNel[A, X] = failureNel[X]}trait ToValidationOps {implicit def ToValidationOps[A](a: A) = new ValidationOps(a)}`

` 1 for { 2 a <- 3.success 3 b <- 2.success 4 } yield a + b //> res7: scalaz.Validation[Nothing,Int] = Success(5) 5 6 val pv = for { 7 a <- 3.success 8 c <- "oh, error!".failure[String] 9 d <- "oh, error again!".failure[String]10 b <- 2.success11 } yield a + b //> pv : scalaz.Validation[String,Int] = Failure(oh, error!)12 if (pv.isFailure) (~pv).getOrElse("no error") //> res8: Any = oh, error!`

`final class ValidationFlatMap[E, A] private[scalaz](val self: Validation[E, A]) {/** Bind through the success of this validation. */def flatMap[EE >: E, B](f: A => Validation[EE, B]): Validation[EE, B] =self match {case Success(a) => f(a)case e @ Failure(_) => e}}`

` @deprecated("""flatMap does not accumulate errors, use `scalaz.\/` or `import scalaz.Validation.FlatMap._` instead""", "7.1")@inline implicit def ValidationFlatMapDeprecated[E, A](d: Validation[E, A]): ValidationFlatMap[E, A] =new ValidationFlatMap(d)/** Import this if you wish to use `flatMap` without a deprecation* warning.*/object FlatMap {@inline implicit def ValidationFlatMapRequested[E, A](d: Validation[E, A]): ValidationFlatMap[E, A] =new ValidationFlatMap(d)}`

` /** Apply a function in the environment of the success of this validation, accumulating errors. */def ap[EE >: E, B](x: => Validation[EE, A => B])(implicit E: Semigroup[EE]): Validation[EE, B] = (this, x) match {case (Success(a), Success(f)) => Success(f(a))case (e @ Failure(_), Success(_)) => ecase (Success(_), e @ Failure(_)) => ecase (Failure(e1), Failure(e2)) => Failure(E.append(e2, e1))}`

`((3.success : Validation[String,Int]) |@|("oh, error1! ".failure : Validation[String,Int]) |@|(2.success : Validation[String,Int]) |@|("oh, error2 again!".failure : Validation[String,Int])){_ + _ + _ + _}//> res13: scalaz.Validation[String,Int] = Failure(oh, error1! oh, error2 again!)`

`((3.successNel : ValidationNel[String,Int]) |@|("oh, error1! ".failureNel : ValidationNel[String,Int]) |@|(2.successNel : ValidationNel[String,Int]) |@|("oh, error2 again!".failureNel : ValidationNel[String,Int])){_ + _ + _ + _}//> res14: scalaz.Validation[scalaz.NonEmptyList[String],Int] = Failure(NonEmptyList(oh, error1! , oh, error2 again!))`

`/** A singly-linked list that is guaranteed to be non-empty. */final class NonEmptyList[+A] private[scalaz](val head: A, val tail: List[A]) {...`

`final class NelOps[A](self: A) {final def wrapNel: NonEmptyList[A] =NonEmptyList(self)}trait ToNelOps {implicit def ToNelOps[A](a: A) = new NelOps(a)}`

`1 val nel = 2 <:: 4 <:: 3.wrapNel //> nel : scalaz.NonEmptyList[Int] = NonEmptyList(2, 4, 3)2 val snel = "one" <:: "two" <:: "three".wrapNel //> snel : scalaz.NonEmptyList[String] = NonEmptyList(one, two, three)3 nel.list //> res17: List[Int] = List(2, 4, 3)4 snel.list //> res18: List[String] = List(one, two, three)`