package scalaz import Id._ /** * Represents either: * - `Success(a)`, or * - `Failure(e)`. * * Isomorphic to `scala.Either` and `scalaz.\/`. The motivation for a `Validation` is to provide the instance * `Applicative[[a]Validation[E, a]]` that accumulate failures through a [[scalaz.Semigroup]]`[E]`. * * [[scalaz.NonEmptyList]] is commonly chosen as a type constructor for the type `E`. As a convenience, * an alias `scalaz.ValidationNel[E]` is provided as a shorthand for `scalaz.Validation[NonEmptyList[E]]`, * and a method `Validation#toValidationNel` converts `Validation[E]` to `ValidationNel[E]`. * * Example: * {{{ * import scalaz._, std.AllInstances._ * * def parseInt(s: String): Validation[String, Int] = * try { Success(s.toInt) } catch { case ex: NumberFormatException => Failure(ex.getMessage) } * val V = Validation.validationNelApplicative[String] * * val x: ValidationNel[String, Int] = * V.map2(parseInt("1.x").toValidationNel, parseInt("1..0").toValidationNel)(_ * _) * // Failure(NonEmptyList(For input string: "1..0", For input string: "1.x")) * }}} * * @tparam E The type of the `Failure` * @tparam A The type of the `Success` */ sealed trait Validation[+E, +A] { import Validation._ sealed trait SwitchingValidation[X] { def s: X def <<?:(fail: => X): X = Validation.this match { case Failure(_) => fail case Success(_) => s } } /** If this validation is success, return the given X value, otherwise, return the X value given to the return value. */ def :?>>[X](success: => X): SwitchingValidation[X] = new SwitchingValidation[X] { def s = success } /** Return `true` if this validation is success. */ def isSuccess: Boolean = this match { case Success(_) => true case Failure(_) => false } /** Return `true` if this validation is failure. */ def isFailure: Boolean = !isSuccess /** Catamorphism. Run the first given function if failure, otherwise, the second given function. */ def fold[X](fail: E => X, succ: A => X): X = this match { case Success(x) => succ(x) case Failure(x) => fail(x) } /** 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) /** Flip the failure/success values in this validation. Alias for `swap` */ def unary_~ : Validation[A, E] = swap /** 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) } /** Run the given function on this swapped value. Alias for `~` */ def swapped[EE, AA](k: Validation[A, E] => Validation[AA, EE]): Validation[EE, AA] = k(swap).swap /** Run the given function on this swapped value. Alias for `swapped` */ def ~[EE, AA](k: Validation[A, E] => Validation[AA, EE]): Validation[EE, AA] = swapped(k) /** Binary functor map on this validation. */ def bimap[C, D](f: E => C, g: A => D): Validation[C, D] = this match { case Failure(a) => Failure(f(a)) case Success(b) => Success(g(b)) } /** Run the given function on the left value. */ def leftMap[C](f: E => C): Validation[C, A] = bimap(f, identity) /** Binary functor traverse on this validation. */ def bitraverse[G[+_] : Functor, C, D](f: E => G[C], g: A => G[D]): G[Validation[C, D]] = this match { case Failure(a) => Functor[G].map(f(a))(Failure(_)) case Success(b) => Functor[G].map(g(b))(Success(_)) } /** Map on the success of this validation. */ def map[B](f: A => B): Validation[E, B] = this match { case Success(a) => Success(f(a)) case Failure(e) => Failure(e) } /** Traverse on the success of this validation. */ def traverse[G[+_] : Applicative, B](f: A => G[B]): G[Validation[E, B]] = this match { case Success(a) => Applicative[G].map(f(a))(Success(_)) case Failure(e) => Applicative[G].point(Failure(e)) } /** Run the side-effect on the success of this validation. */ def foreach[U](f: A => U): Unit = this match { case Success(a) => f(a) case Failure(_) => } /** 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 (Failure(e), Success(_)) => Failure(e) case (Success(f), Failure(e)) => Failure(e) case (Failure(e1), Failure(e2)) => Failure(E.append(e2, e1)) } /** Bind through the success of this validation. */ def flatMap[EE >: E, B](f: A => Validation[EE, B]): Validation[EE, B] = this match { case Success(a) => f(a) case Failure(e) => Failure(e) } /** Fold on the success of this validation. */ def foldRight[B](z: => B)(f: (A, => B) => B): B = this match { case Success(a) => f(a, z) case Failure(_) => z } /** Filter on the success of this validation. */ def filter[EE >: E](p: A => Boolean)(implicit M: Monoid[EE]): Validation[EE, A] = this match { case Failure(a) => Failure(a) case Success(e) => if(p(e)) Success(e) else Failure(M.zero) } /** Return `true` if this validation is a success value satisfying the given predicate. */ def exists(f: A => Boolean): Boolean = this match { case Success(a) => f(a) case Failure(_) => false } /** Return `true` if this validation is a failure value or the success value satisfies the given predicate. */ def forall(f: A => Boolean): Boolean = this match { case Success(a) => f(a) case Failure(_) => true } /** Return an empty list or list with one element on the success of this validation. */ def toList: List[A] = this match { case Failure(_) => Nil case Success(a) => List(a) } /** Return an empty stream or stream with one element on the success of this validation. */ def toStream: Stream[A] = this match { case Failure(_) => Stream() case Success(a) => Stream(a) } /** Return an empty option or option with one element on the success of this validation. Useful to sweep errors under the carpet. */ def toOption: Option[A] = this match { case Failure(_) => None case Success(a) => Some(a) } /** Convert to a core `scala.Either` at your own peril. */ def toEither: Either[E, A] = this match { case Success(a) => Right(a) case Failure(e) => Left(e) } /** Return the success value of this validation or the given default if failure. Alias for `|` */ def getOrElse[AA >: A](x: => AA): AA = toOption getOrElse x /** 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(_) => x case 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) /** * Sums up values inside validation, if both are success or failure. Returns first failure otherwise. * {{{ * success(v1) +++ success(v2) → success(v1 + v2) * success(v1) +++ failure(v2) → failure(v2) * failure(v1) +++ success(v2) → failure(v1) * failure(v1) +++ failure(v2) → failure(v1 + v2) * }}} */ def +++[EE >: E, AA >: A](x: => Validation[EE, AA])(implicit M1: Semigroup[AA], M2: Semigroup[EE]): Validation[EE, AA] = this match { case Failure(a1) => x match { case Failure(a2) => Failure(M2.append(a1, a2)) case Success(b2) => Failure(a1) } case Success(b1) => x match { case Failure(a2) => Failure(a2) case Success(b2) => Success(M1.append(b1, b2)) } } /** Ensures that the success value of this validation satisfies the given predicate, or fails with the given value. */ def ensure[EE >: E](onFailure: => EE)(f: A => Boolean): Validation[EE, A] = this match { case Success(a) => if (f(a)) this else Failure(onFailure) case Failure(_) => this } /** Compare two validations values for equality. */ def ===[EE >: E, AA >: A](x: => Validation[EE, AA])(implicit EE: Equal[EE], EA: Equal[AA]): Boolean = this match { case Failure(e1) => x match { case Failure(e2) => Equal[EE].equal(e1, e2) case Success(_) => false } case Success(a1) => x match { case Success(a2) => Equal[AA].equal(a1, a2) case Failure(_) => false } } /** Compare two validations values for ordering. */ def compare[EE >: E, AA >: A](x: => Validation[EE, AA])(implicit EE: Order[EE], EA: Order[AA]): Ordering = this match { case Failure(e1) => x match { case Failure(e2) => Order[EE].apply(e1, e2) case Success(_) => Ordering.LT } case Success(a1) => x match { case Success(a2) => Order[AA].apply(a1, a2) case Failure(_) => Ordering.GT } } /** Show for a validation value. */ def show[EE >: E, AA >: A](implicit SE: Show[EE], SA: Show[AA]): Cord = this match { case Failure(e) => ("Failure(": Cord) ++ Show[EE].show(e) :- ')' case Success(a) => ("Success(": Cord) ++ Show[AA].show(a) :- ')' } /** If `this` and `that` are both success, or both a failure, combine them with the provided `Semigroup` for each. Otherwise, return the success. Alias for `+|+` */ def append[EE >: E, AA >: A](that: Validation[EE, AA])(implicit es: Semigroup[EE], as: Semigroup[AA]): Validation[EE, AA] = (this, that) match { case (Success(a1), Success(a2)) => Success(as.append(a1, a2)) case (Success(_), Failure(_)) => this case (Failure(_), Success(_)) => that case (Failure(e1), Failure(e2)) => Failure(es.append(e1, e2)) } /** If `this` and `that` are both success, or both a failure, combine them with the provided `Semigroup` for each. Otherwise, return the success. Alias for `append` */ def +|+[EE >: E, AA >: A](x: Validation[EE, AA])(implicit es: Semigroup[EE], as: Semigroup[AA]): Validation[EE, AA] = append(x) /** If `this` is a success, return it; otherwise, if `that` is a success, return it; otherwise, combine the failures with the specified semigroup. */ def findSuccess[EE >: E, AA >: A](that: => Validation[EE, AA])(implicit es: Semigroup[EE]): Validation[EE, AA] = this match { case Failure(e) => that match { case Failure(e0) => Failure(es.append(e, e0)) case success => success } case success => success } /** Wraps the failure value in a [[scalaz.NonEmptyList]] */ def toValidationNel[EE >: E, AA >: A]: ValidationNel[EE, AA] = this match { case Success(a) => Success(a) case Failure(e) => Failure(NonEmptyList(e)) } /** Convert to a disjunction. */ def disjunction: (E \/ A) = this match { case Success(a) => \/-(a) case Failure(e) => -\/(e) } /** Run a disjunction function and back to validation again. Alias for `@\/` */ def disjunctioned[EE, AA](k: (E \/ A) => (EE \/ AA)): Validation[EE, AA] = k(disjunction).validation /** Run a disjunction function and back to validation again. Alias for `disjunctioned` */ def @\/[EE, AA](k: (E \/ A) => (EE \/ AA)): Validation[EE, AA] = disjunctioned(k) } final case class Success[E, A](a: A) extends Validation[E, A] final case class Failure[E, A](e: E) extends Validation[E, A] 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) } } trait ValidationInstances extends ValidationInstances0 { type \?/[+E, +A] = Validation[E, A] } trait ValidationInstances0 extends ValidationInstances1 { implicit def ValidationOrder[E: Order, A: Order]: Order[Validation[E, A]] = new Order[Validation[E, A]] { def order(f1: Validation[E, A], f2: Validation[E, A]) = f1 compare f2 } implicit def ValidationMonoid[E: Semigroup, A: Monoid]: Monoid[Validation[E, A]] = new Monoid[Validation[E, A]] { def append(a1: Validation[E, A], a2: => Validation[E, A]) = a1 +++ a2 def zero = Success(Monoid[A].zero) } } trait ValidationInstances1 extends ValidationInstances2 { implicit def ValidationEqual[E: Equal, A: Equal]: Equal[Validation[E, A]] = new Equal[Validation[E, A]] { def equal(a1: Validation[E, A], a2: Validation[E, A]) = a1 === a2 } implicit def ValidationShow[E: Show, A: Show]: Show[Validation[E, A]] = Show.show(_.show) implicit def ValidationSemigroup[E: Semigroup, A: Semigroup]: Semigroup[Validation[E, A]] = new Semigroup[Validation[E, A]] { def append(a1: Validation[E, A], a2: => Validation[E, A]) = a1 +++ a2 } } trait ValidationInstances2 extends ValidationInstances3 { implicit def ValidationInstances1[L]: Traverse[({type l[a] = Validation[L, a]})#l] with Cozip[({type l[a] = Validation[L, a]})#l] with Plus[({type l[a] = Validation[L, a]})#l] = new Traverse[({type l[a] = Validation[L, a]})#l] with Cozip[({type l[a] = Validation[L, a]})#l] with Plus[({type l[a] = Validation[L, a]})#l] { override def map[A, B](fa: Validation[L, A])(f: A => B) = fa map f def traverseImpl[G[+_] : Applicative, A, B](fa: Validation[L, A])(f: A => G[B]) = fa.traverse(f) override def foldRight[A, B](fa: Validation[L, A], z: => B)(f: (A, => B) => B) = fa.foldRight(z)(f) def cozip[A, B](x: Validation[L, A \/ B]) = x match { case Failure(l) => -\/(Failure(l)) case Success(e) => e match { case -\/(a) => -\/(Success(a)) case \/-(b) => \/-(Success(b)) } } def plus[A](a: Validation[L, A], b: => Validation[L, A]) = a orElse b } } trait ValidationInstances3 { implicit def ValidationInstances0 : Bitraverse[Validation] = new Bitraverse[Validation] { override def bimap[A, B, C, D](fab: Validation[A, B]) (f: A => C, g: B => D) = fab bimap (f, g) def bitraverseImpl[G[+_] : Applicative, A, B, C, D](fab: Validation[A, B]) (f: A => G[C], g: B => G[D]) = fab.bitraverse(f, g) } implicit def ValidationApplicative[L: Semigroup]: Applicative[({type l[a] = Validation[L, a]})#l] = new Applicative[({type l[a] = Validation[L, a]})#l] { def point[A](a: => A) = Success(a) def ap[A, B](fa: => Validation[L, A])(f: => Validation[L, A => B]) = fa ap f } } trait ValidationFunctions { /** Construct a success validation value. */ def success[E, A]: A => Validation[E, A] = Success(_) /** Construct a failure validation value. */ def failure[E, A]: E => Validation[E, A] = Failure(_) /** Evaluate the given value, which might throw an exception. */ def fromTryCatch[T](a: => T): Validation[Throwable, T] = try { success(a) } catch { case e => failure(e) } /** Construct a `Validation` from an `Either`. */ def fromEither[E, A](e: Either[E, A]): Validation[E, A] = e.fold(failure, success) }