scalaz.Either.scala Maven / Gradle / Ivy
package scalaz
import scala.util.control.NonFatal
import scala.reflect.ClassTag
import Liskov.<~<
/** Represents a disjunction: a result that is either an `A` or a `B`.
*
* An instance of `A` [[\/]] B is either a [[-\/]]`[A]` (aka a "left") or a [[\/-]]`[B]` (aka a "right").
*
* A common use of a disjunction is to explicitly represent the possibility of failure in a result as opposed to
* throwing an exception. By convention, the left is used for errors and the right is reserved for successes.
* For example, a function that attempts to parse an integer from a string may have a return type of
* `NumberFormatException` [[\/]] `Int`. However, since there is no need to actually throw an exception, the type (`A`)
* chosen for the "left" could be any type representing an error and has no need to actually extend `Exception`.
*
* `A` [[\/]] `B` is isomorphic to `scala.Either[A, B]`, but [[\/]] is right-biased, so methods such as `map` and
* `flatMap` apply only in the context of the "right" case. This right bias makes [[\/]] more convenient to use
* than `scala.Either` in a monadic context. Methods such as `swap`, `swapped`, and `leftMap` provide functionality
* that `scala.Either` exposes through left projections.
*
* `A` [[\/]] `B` is also isomorphic to [[Validation]]`[A, B]`. The subtle but important difference is that [[Applicative]]
* instances for [[Validation]] accumulates errors ("lefts") while [[Applicative]] instances for [[\/]] fail fast on the
* first "left" they evaluate. This fail-fast behavior allows [[\/]] to have lawful [[Monad]] instances that are consistent
* with their [[Applicative]] instances, while [[Validation]] cannot.
*/
sealed abstract class \/[+A, +B] extends Product with Serializable {
final class SwitchingDisjunction[X](r: => X) {
def < X): X =
\/.this match {
case -\/(_) => left
case \/-(_) => r
}
}
/** If this disjunction is right, return the given X value, otherwise, return the X value given to the return value. */
def :?>>[X](right: => X): SwitchingDisjunction[X] =
new SwitchingDisjunction[X](right)
/** Return `true` if this disjunction is left. */
def isLeft: Boolean =
this match {
case -\/(_) => true
case \/-(_) => false
}
/** Return `true` if this disjunction is right. */
def isRight: Boolean =
this match {
case -\/(_) => false
case \/-(_) => true
}
/** Catamorphism. Run the first given function if left, otherwise, the second given function. */
def fold[X](l: A => X, r: B => X): X =
this match {
case -\/(a) => l(a)
case \/-(b) => r(b)
}
/** Spin in tail-position on the right value of this disjunction. */
def loopr[AA >: A, BB >: B, X](left: AA => X, right: BB => X \/ (AA \/ BB)): X =
\/.loopRight(this, left, right)
/** Spin in tail-position on the left value of this disjunction. */
def loopl[AA >: A, BB >: B, X](left: AA => X \/ (AA \/ BB), right: BB => X): X =
\/.loopLeft(this, left, right)
/** Flip the left/right values in this disjunction. Alias for `unary_~` */
def swap: (B \/ A) =
this match {
case -\/(a) => \/-(a)
case \/-(b) => -\/(b)
}
/** Flip the left/right values in this disjunction. Alias for `swap` */
def unary_~ : (B \/ A) =
swap
/** Run the given function on this swapped value. Alias for `~` */
def swapped[AA, BB](k: (B \/ A) => (BB \/ AA)): (AA \/ BB) =
k(swap).swap
/** Run the given function on this swapped value. Alias for `swapped` */
def ~[AA, BB](k: (B \/ A) => (BB \/ AA)): (AA \/ BB) =
swapped(k)
/** Binary functor map on this disjunction. */
def bimap[C, D](f: A => C, g: B => D): (C \/ D) =
this match {
case -\/(a) => -\/(f(a))
case \/-(b) => \/-(g(b))
}
/** Run the given function on the left value. */
def leftMap[C](f: A => C): (C \/ B) =
this match {
case -\/(a) => -\/(f(a))
case b @ \/-(_) => b
}
/** Binary functor traverse on this disjunction. */
def bitraverse[F[_]: Functor, C, D](f: A => F[C], g: B => F[D]): F[C \/ D] =
this match {
case -\/(a) => Functor[F].map(f(a))(\/.left)
case \/-(b) => Functor[F].map(g(b))(\/.right)
}
/** Map on the right of this disjunction. */
def map[D](g: B => D): (A \/ D) =
this match {
case \/-(a) => \/-(g(a))
case b @ -\/(_) => b
}
/** Traverse on the right of this disjunction. */
def traverse[F[_]: Applicative, AA >: A, D](g: B => F[D]): F[AA \/ D] =
this match {
case a @ -\/(_) => Applicative[F].point(a)
case \/-(b) => Functor[F].map(g(b))(\/.right)
}
/** Run the side-effect on the right of this disjunction. */
def foreach(g: B => Unit): Unit =
bimap(_ => (), g)
/** Apply a function in the environment of the right of this disjunction. */
def ap[AA >: A, C](f: => AA \/ (B => C)): (AA \/ C) =
f flatMap (ff => map(ff(_)))
/** Bind through the right of this disjunction. */
def flatMap[AA >: A, D](g: B => (AA \/ D)): (AA \/ D) =
this match {
case a @ -\/(_) => a
case \/-(b) => g(b)
}
/** Fold on the right of this disjunction. */
def foldRight[Z](z: => Z)(f: (B, => Z) => Z): Z =
this match {
case -\/(_) => z
case \/-(a) => f(a, z)
}
/** Filter on the right of this disjunction. */
def filter[AA >: A](p: B => Boolean)(implicit M: Monoid[AA]): (AA \/ B) =
this match {
case -\/(_) => this
case \/-(b) => if(p(b)) this else -\/(M.zero)
}
/** Return `true` if this disjunction is a right value satisfying the given predicate. */
def exists[BB >: B](p: BB => Boolean): Boolean =
this match {
case -\/(_) => false
case \/-(b) => p(b)
}
/** Return `true` if this disjunction is a left value or the right value satisfies the given predicate. */
def forall[BB >: B](p: BB => Boolean): Boolean =
this match {
case -\/(_) => true
case \/-(b) => p(b)
}
/** Return an empty list or list with one element on the right of this disjunction. */
def toList: List[B] =
this match {
case -\/(_) => Nil
case \/-(b) => b :: Nil
}
/** Return an empty stream or stream with one element on the right of this disjunction. */
def toStream: Stream[B] =
this match {
case -\/(_) => Stream()
case \/-(b) => Stream(b)
}
/** Return an empty option or option with one element on the right of this disjunction. Useful to sweep errors under the carpet. */
def toOption: Option[B] =
this match {
case -\/(_) => None
case \/-(b) => Some(b)
}
/** Return an empty maybe or option with one element on the right of this disjunction. Useful to sweep errors under the carpet. */
def toMaybe[BB >: B]: Maybe[BB] =
this match {
case -\/(_) => Maybe.empty
case \/-(b) => Maybe.just(b)
}
/** Convert to a core `scala.Either` at your own peril. */
def toEither: Either[A, B] =
this match {
case -\/(a) => Left(a)
case \/-(b) => Right(b)
}
/** Return the right value of this disjunction or the given default if left. Alias for `|` */
def getOrElse[BB >: B](x: => BB): BB =
this match {
case -\/(_) => x
case \/-(b) => b
}
/** Return the right value of this disjunction or the given default if left. Alias for `getOrElse` */
def |[BB >: B](x: => BB): BB =
getOrElse(x)
/** Return the right value of this disjunction or run the given function on the left. */
def valueOr[BB >: B](x: A => BB): BB =
this match {
case -\/(a) => x(a)
case \/-(b) => b
}
/** Return this if it is a right, otherwise, return the given value. Alias for `|||` */
def orElse[C, BB >: B](x: => C \/ BB): C \/ BB =
this match {
case -\/(_) => x
case right@ \/-(_) => right
}
/** Return this if it is a right, otherwise, return the given value. Alias for `orElse` */
def |||[C, BB >: B](x: => C \/ BB): C \/ BB =
orElse(x)
/**
* Sums up values inside disjunction, if both are left or right. Returns first left otherwise.
* {{{
* \/-(v1) +++ \/-(v2) → \/-(v1 + v2)
* \/-(v1) +++ -\/(v2) → -\/(v2)
* -\/(v1) +++ \/-(v2) → -\/(v1)
* -\/(v1) +++ -\/(v2) → -\/(v1 + v2)
* }}}
*/
def +++[AA >: A, BB >: B](x: => AA \/ BB)(implicit M1: Semigroup[BB], M2: Semigroup[AA]): AA \/ BB =
this match {
case -\/(a1) => x match {
case -\/(a2) => -\/(M2.append(a1, a2))
case \/-(_) => this
}
case \/-(b1) => x match {
case b2 @ -\/(_) => b2
case \/-(b2) => \/-(M1.append(b1, b2))
}
}
/** Ensures that the right value of this disjunction satisfies the given predicate, or returns left with the given value. */
def ensure[AA >: A](onLeft: => AA)(f: B => Boolean): (AA \/ B) = this match {
case \/-(b) => if (f(b)) this else -\/(onLeft)
case -\/(_) => this
}
/** Run the given function on the left and return right with the result. */
def recover[BB >: B](pf: PartialFunction[A, BB]): (A \/ BB) = this match {
case -\/(a) if (pf isDefinedAt a) => \/-(pf(a))
case _ => this
}
/** Run the given function on the left and return the result. */
def recoverWith[AA >: A, BB >: B](pf: PartialFunction[AA, AA \/ BB]): (AA \/ BB) = this match {
case -\/(a) if (pf isDefinedAt a) => pf(a)
case _ => this
}
/** Compare two disjunction values for equality. */
def ===[AA >: A, BB >: B](x: AA \/ BB)(implicit EA: Equal[AA], EB: Equal[BB]): Boolean =
this match {
case -\/(a1) => x match {
case -\/(a2) => Equal[AA].equal(a1, a2)
case \/-(_) => false
}
case \/-(b1) => x match {
case \/-(b2) => Equal[BB].equal(b1, b2)
case -\/(_) => false
}
}
/** Compare two disjunction values for ordering. */
def compare[AA >: A, BB >: B](x: AA \/ BB)(implicit EA: Order[AA], EB: Order[BB]): Ordering =
this match {
case -\/(a1) => x match {
case -\/(a2) => Order[AA].apply(a1, a2)
case \/-(_) => Ordering.LT
}
case \/-(b1) => x match {
case \/-(b2) => Order[BB].apply(b1, b2)
case -\/(_) => Ordering.GT
}
}
/** Show for a disjunction value. */
def show[AA >: A, BB >: B](implicit SA: Show[AA], SB: Show[BB]): Cord =
this match {
case -\/(a) => ("-\\/(": Cord) ++ SA.show(a) :- ')'
case \/-(b) => ("\\/-(": Cord) ++ SB.show(b) :- ')'
}
/** Convert to a Validation. */
def validation: Validation[A, B] =
this match {
case -\/(a) => Failure(a)
case \/-(b) => Success(b)
}
/** Convert to a ValidationNel. */
def validationNel[AA>:A] : ValidationNel[AA,B] =
this match {
case -\/(a) => Failure(NonEmptyList(a))
case \/-(b) => Success(b)
}
/** Run a validation function and back to disjunction again. Alias for `@\?/` */
def validationed[AA, BB](k: Validation[A, B] => Validation[AA, BB]): AA \/ BB =
k(validation).disjunction
/** Run a validation function and back to disjunction again. Alias for `validationed` */
def @\?/[AA, BB](k: Validation[A, B] => Validation[AA, BB]): AA \/ BB =
validationed(k)
/** Return the value from whichever side of the disjunction is defined, given a commonly assignable type. */
def merge[AA >: A](implicit ev: B <~< AA): AA =
this match {
case -\/(a) => a
case \/-(b) => ev(b)
}
/** Convert to a These. */
def toThese: A \&/ B =
fold(
a => \&/.This(a),
b => \&/.That(b)
)
}
/** A left disjunction
*
* Often used to represent the failure case of a result
*/
final case class -\/[+A](a: A) extends (A \/ Nothing)
/** A right disjunction
*
* Often used to represent the success case of a result
*/
final case class \/-[+B](b: B) extends (Nothing \/ B)
object \/ extends DisjunctionInstances {
/** Construct a left disjunction value. */
def left[A, B]: A => A \/ B =
-\/(_)
/** Construct a right disjunction value. */
def right[A, B]: B => A \/ B =
\/-(_)
/** Construct a disjunction value from a standard `scala.Either`. */
def fromEither[A, B](e: Either[A, B]): A \/ B =
e fold (left, right)
def fromTryCatchThrowable[T, E <: Throwable](a: => T)(implicit nn: NotNothing[E], ex: ClassTag[E]): E \/ T = try {
\/-(a)
} catch {
case e if ex.runtimeClass.isInstance(e) => -\/(e.asInstanceOf[E])
}
def fromTryCatchNonFatal[T](a: => T): Throwable \/ T = try {
\/-(a)
} catch {
case NonFatal(t) => -\/(t)
}
/** Spin in tail-position on the right value of the given disjunction. */
@annotation.tailrec
final def loopRight[A, B, X](d: A \/ B, left: A => X, right: B => X \/ (A \/ B)): X =
d match {
case -\/(a) => left(a)
case \/-(b) => right(b) match {
case -\/(x) => x
case \/-(q) => loopRight(q, left, right)
}
}
/** Spin in tail-position on the left value of the given disjunction. */
@annotation.tailrec
final def loopLeft[A, B, X](d: A \/ B, left: A => X \/ (A \/ B), right: B => X): X =
d match {
case -\/(a) => left(a) match {
case -\/(x) => x
case \/-(q) => loopLeft(q, left, right)
}
case \/-(b) => right(b)
}
}
sealed abstract class DisjunctionInstances extends DisjunctionInstances0 {
implicit def DisjunctionOrder[A: Order, B: Order]: Order[A \/ B] =
new Order[A \/ B] {
def order(a1: A \/ B, a2: A \/ B) =
a1 compare a2
override def equal(a1: A \/ B, a2: A \/ B) =
a1 === a2
}
implicit def DisjunctionMonoid[A: Semigroup, B: Monoid]: Monoid[A \/ B] =
new Monoid[A \/ B] {
def append(a1: A \/ B, a2: => A \/ B) =
a1 +++ a2
def zero =
\/-(Monoid[B].zero)
}
}
sealed abstract class DisjunctionInstances0 extends DisjunctionInstances1 {
implicit def DisjunctionEqual[A: Equal, B: Equal]: Equal[A \/ B] =
new Equal[A \/ B] {
def equal(a1: A \/ B, a2: A \/ B) =
a1 === a2
}
implicit def DisjunctionShow[A: Show, B: Show]: Show[A \/ B] =
Show.show(_.show)
implicit def DisjunctionSemigroup[A: Semigroup, B: Semigroup]: Semigroup[A \/ B] =
new Semigroup[A \/ B] {
def append(a1: A \/ B, a2: => A \/ B) =
a1 +++ a2
}
}
sealed abstract class DisjunctionInstances1 extends DisjunctionInstances2 {
implicit def DisjunctionInstances1[L]: Traverse[L \/ ?] with Monad[L \/ ?] with BindRec[L \/ ?] with Cozip[L \/ ?] with Plus[L \/ ?] with Optional[L \/ ?] with MonadError[L \/ ?, L] =
new Traverse[L \/ ?] with Monad[L \/ ?] with BindRec[L \/ ?] with Cozip[L \/ ?] with Plus[L \/ ?] with Optional[L \/ ?] with MonadError[L \/ ?, L] {
override def map[A, B](fa: L \/ A)(f: A => B) =
fa map f
@scala.annotation.tailrec
def tailrecM[A, B](f: A => L \/ (A \/ B))(a: A): L \/ B =
f(a) match {
case l @ -\/(_) => l
case \/-(-\/(a0)) => tailrecM(f)(a0)
case \/-(rb @ \/-(_)) => rb
}
def bind[A, B](fa: L \/ A)(f: A => L \/ B) =
fa flatMap f
def point[A](a: => A) =
\/-(a)
def traverseImpl[G[_] : Applicative, A, B](fa: L \/ A)(f: A => G[B]) =
fa.traverse(f)
override def foldRight[A, B](fa: L \/ A, z: => B)(f: (A, => B) => B) =
fa.foldRight(z)(f)
def cozip[A, B](x: L \/ (A \/ B)) =
x match {
case l @ -\/(_) => -\/(l)
case \/-(e) => e match {
case -\/(a) => -\/(\/-(a))
case b @ \/-(_) => \/-(b)
}
}
def plus[A](a: L \/ A, b: => L \/ A) =
a orElse b
def pextract[B, A](fa: L \/ A): (L \/ B) \/ A = fa match {
case l@ -\/(_) => -\/(l)
case r@ \/-(_) => r
}
def raiseError[A](e: L): L \/ A =
-\/(e)
def handleError[A](fa: L \/ A)(f: L => L \/ A): L \/ A = fa match {
case -\/(e) => f(e)
case r => r
}
}
}
sealed abstract class DisjunctionInstances2 {
implicit val DisjunctionInstances2 : Bitraverse[\/] = new Bitraverse[\/] {
override def bimap[A, B, C, D](fab: A \/ B)
(f: A => C, g: B => D) = fab bimap (f, g)
def bitraverseImpl[G[_] : Applicative, A, B, C, D](fab: A \/ B)
(f: A => G[C], g: B => G[D]) =
fab.bitraverse(f, g)
}
implicit val DisjunctionAssociative: Associative[\/] = new Associative[\/] {
def reassociateLeft[A, B, C](f: \/[A, \/[B, C]]) =
f.fold(
a => -\/(-\/(a)),
_.fold(
b => -\/(\/-(b)),
\/.right
)
)
def reassociateRight[A, B, C](f: \/[\/[A, B], C]) =
f.fold(
_.fold(
\/.left,
b => \/-(-\/(b))
),
c => \/-(\/-(c))
)
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy