package scala /** *
* The Either
type represents a value of one of two possible types (a disjoint union).
* The data constructors; Left
and Right
represent the two possible
* values. The Either
type is often used as an alternative to
* scala.Option
where Left
represents failure (by convention) and
* Right
is akin to Some
.
*
Either
as a Left
.
*/
def left = Either.LeftProjection(this)
/**
* Projects this Either
as a Right
.
*/
def right = Either.RightProjection(this)
/**
* Deconstruction of the Either
type (in contrast to pattern matching).
*/
def fold[X](fa: A => X, fb: B => X) = this match {
case Left(a) => fa(a)
case Right(b) => fb(b)
}
/**
* If this is a Left
, then return the left value in Right
or vice versa.
*/
def swap = this match {
case Left(a) => Right(a)
case Right(b) => Left(b)
}
/**
* Returns true
if this is a Left
, false
otherwise.
*/
def isLeft = false // Default here, overriden in Left
/**
* Returns true
if this is a Right
, false
otherwise.
*/
def isRight = false // Default here, overriden in Right.
}
/**
* The left side of the disjoint union, as opposed to the Right
side.
*
* @author Tony Morris, Workingmouse
* @version 1.0, 11/10/2008
*/
final case class Left[+A, +B](a: A) extends Either[A, B] { override def isLeft = true }
/**
* The right side of the disjoint union, as opposed to the Left
side.
*
* @author Tony Morris, Workingmouse
* @version 1.0, 11/10/2008
*/
final case class Right[+A, +B](b: B) extends Either[A, B] { override def isRight = true }
object Either {
/**
* Returns the Left
values in the given Iterable
of Either
s.
*/
@deprecated("use `for (Left(a) <- es) yield a'")
def lefts[A, B](es: Iterable[Either[A, B]]) =
es.foldRight[List[A]](Nil)((e, as) => e match {
case Left(a) => a :: as
case Right(_) => as
})
/**
* Returns the Right
values in the givenIterable
of Either
s.
*/
@deprecated("use `for (Right(a) <- es) yield a'")
def rights[A, B](es: Iterable[Either[A, B]]) =
es.foldRight[List[B]](Nil)((e, bs) => e match {
case Left(_) => bs
case Right(b) => b :: bs
})
/** Transforms an Iterable of Eithers into a pair of lists.
*
* @param xs the iterable of Eithers to separate
* @return a pair of lists.
*/
@deprecated("use `for ((Left(l), Right(r)) <- es partition isLeft) yield (l, r)'")
def separate[A,B](es: Iterable[Either[A,B]]): (List[A], List[B]) =
es.foldRight[(List[A], List[B])]((Nil, Nil)) {
case (Left(a), (lefts, rights)) => (a :: lefts, rights)
case (Right(b), (lefts, rights)) => (lefts, b :: rights)
}
/**
* Projects an Either
into a Left
.
*
* @author Tony Morris, Workingmouse
* @version 1.0, 11/10/2008
*/
final case class LeftProjection[+A, +B](e: Either[A, B]) {
/**
* Returns the value from this Left
or throws Predef.NoSuchElementException
* if this is a Right
.
*
* @throws Predef.NoSuchElementException if the option is empty.
*/
def get = e match {
case Left(a) => a
case Right(_) => throw new NoSuchElementException("Either.left.value on Right")
}
/**
* Executes the given side-effect if this is a Left
.
*
* @param e The side-effect to execute.
*/
def foreach[U](f: A => U) = e match {
case Left(a) => f(a)
case Right(_) => {}
}
/**
* Returns the value from this Left
or the given argument if this is a
* Right
.
*/
def getOrElse[AA >: A](or: => AA) = e match {
case Left(a) => a
case Right(_) => or
}
/**
* Returns true
if Right
or returns the result of the application of
* the given function to the Left
value.
*/
def forall(f: A => Boolean) = e match {
case Left(a) => f(a)
case Right(_) => true
}
/**
* Returns false
if Right
or returns the result of the application of
* the given function to the Left
value.
*/
def exists(f: A => Boolean) = e match {
case Left(a) => f(a)
case Right(_) => false
}
/**
* Binds the given function across Left
.
*
* @param The function to bind across Left
.
*/
def flatMap[BB >: B, X](f: A => Either[X, BB]) = e match {
case Left(a) => f(a)
case Right(b) => Right(b)
}
/**
* Maps the function argument through Left
.
*/
def map[X](f: A => X) = e match {
case Left(a) => Left(f(a))
case Right(b) => Right(b)
}
/**
* Returns None
if this is a Right
or if the given predicate
* p
does not hold for the left value, otherwise, returns a Left
.
*/
def filter[Y](p: A => Boolean): Option[Either[A, Y]] = e match {
case Left(a) => if(p(a)) Some(Left(a)) else None
case Right(b) => None
}
/**
* Returns a Seq
containing the Left
value if it exists or an empty
* Seq
if this is a Right
.
*/
def toSeq = e match {
case Left(a) => Seq(a)
case Right(_) => Seq.empty
}
/**
* Returns a Some
containing the Left
value if it exists or a
* None
if this is a Right
.
*/
def toOption = e match {
case Left(a) => Some(a)
case Right(_) => None
}
}
/**
* Projects an Either
into a Right
.
*
* @author Tony Morris, Workingmouse
* @version 1.0, 11/10/2008
*/
final case class RightProjection[+A, +B](e: Either[A, B]) {
/**
* Returns the value from this Right
or throws
* Predef.NoSuchElementException
if this is a Left
.
*
* @throws Predef.NoSuchElementException if the projection is Left
.
*/
def get = e match {
case Left(_) => throw new NoSuchElementException("Either.right.value on Left")
case Right(a) => a
}
/**
* Executes the given side-effect if this is a Right
.
*
* @param e The side-effect to execute.
*/
def foreach[U](f: B => U) = e match {
case Left(_) => {}
case Right(b) => f(b)
}
/**
* Returns the value from this Right
or the given argument if this is a
* Left
.
*/
def getOrElse[BB >: B](or: => BB) = e match {
case Left(_) => or
case Right(b) => b
}
/**
* Returns true
if Left
or returns the result of the application of
* the given function to the Right
value.
*/
def forall(f: B => Boolean) = e match {
case Left(_) => true
case Right(b) => f(b)
}
/**
* Returns false
if Left
or returns the result of the application of
* the given function to the Right
value.
*/
def exists(f: B => Boolean) = e match {
case Left(_) => false
case Right(b) => f(b)
}
/**
* Binds the given function across Right
.
*
* @param The function to bind across Right
.
*/
def flatMap[AA >: A, Y](f: B => Either[AA, Y]) = e match {
case Left(a) => Left(a)
case Right(b) => f(b)
}
/**
* Maps the function argument through Right
.
*/
def map[Y](f: B => Y) = e match {
case Left(a) => Left(a)
case Right(b) => Right(f(b))
}
/**
* Returns None
if this is a Left
or if the given predicate
* p
does not hold for the right value, otherwise, returns a Right
.
*/
def filter[X](p: B => Boolean): Option[Either[X, B]] = e match {
case Left(_) => None
case Right(b) => if(p(b)) Some(Right(b)) else None
}
/**
* Returns a Seq
containing the Right
value if it exists or an empty
* Seq
if this is a Left
.
*/
def toSeq = e match {
case Left(_) => Seq.empty
case Right(b) => Seq(b)
}
/**
* Returns a Some
containing the Right
value if it exists or a
* None
if this is a Left
.
*/
def toOption = e match {
case Left(_) => None
case Right(b) => Some(b)
}
}
/**
* Joins an Either
through Left
.
*/
def joinLeft[A, B](es: Either[Either[A, B], B]) =
es.left.flatMap(x => x)
/**
* Joins an Either
through Right
.
*/
def joinRight[A, B](es: Either[A, Either[A, B]]) =
es.right.flatMap(x => x)
/**
* Takes an Either
to its contained value within Left
or
* Right
.
*/
def merge[T](e: Either[T, T]) = e match {
case Left(t) => t
case Right(t) => t
}
/**
* If the condition satisfies, return the given A in Left
, otherwise, return the
* given B in Right
.
*/
def cond[A, B](test: Boolean, right: => B, left: => A) =
if(test) Right(right) else Left(left)
}