The other answers are very good and this example isn't that practical as the others. I'd just like to add a bit of underlying theory.
What you're describing is often called traversal in functional programming. You have a collection like Seq[X] and a monadic (or applicative) computation X => M[Y]. Standard map gives you Seq[M[Y]], but traversal gives you M[Seq[Y]].
In this case, the monadic computation is something that produces Either[Error,Right], in this case M[_] is Either[Error,_]. So if you just map over a collection with such a function, you get Seq[Either[Error,Right]]. But what you want is Either[Error,Seq[Right]] and that's exactly what traversal does. If the function fails on any element of the sequence (returns Left(something)) then the final result is just this Left(something). If the function succeeds on all the elements (returns Right(...) for all of them) then the final result is Right(sequenceOfResults).
Scala doesn't have a built-in function for that, but Scalaz does, it's called traverse. A complete example:
import scalaz._;
import Scalaz._;
import Applicative._;
object RightMatch extends App {
// our example function
def foo(s: String): Either[String,Int] =
if (s.startsWith("a")) Right(s.length)
else Left("wrong: " + s);
// We make an utility function for traversing Sequences wit Eithers:
def traverseRight[X,L,R](es: Seq[X], f: X => Either[L,R]): Either[L,Seq[R]] = {
// we need to convert Either to Either.RightProjection
type RightF[Y] = Either.RightProjection[L,Y];
es.traverse[RightF,R](x => f(x).right).e; // and back to Either
}
// Or, if we just want to convert an existing sequence of eithers:
def traverseRight[L,R](es: Seq[Either[L,R]]): Either[L,Seq[R]] =
traverseRight(es, identity[Either[L,R]]);
{
val a = Seq("a", "ab", "ac");
traverseRight(a, foo) match {
case Right(arr) => println(arr); // we get the array of Ints here
case Left(err) => println(err); // we get String here (the first error)
}
}
}
(Note that in Scalaz Array has not an implementation of traversable (I don't know why), so I used Seq instead.)
As mentioned, traversal applies not just to Eithers, it applies to any monadic computations. So the same approach can be used for a vast range of problems, like sequencing stateful computations (modelled by scalaz's State), sequencing non-deterministic computations (the List monad) etc.
Either.RightProjection[Baz]will be preferred.