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. *

* * @author Tony Morris, Workingmouse * @version 1.0, 11/10/2008 * @since 2.7 */ sealed abstract class Either[+A, +B] { /** * Projects this 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 Eithers. */ @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 Eithers. */ @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) }