Search code examples
scalascala-cats

Scala - Flatten Sequence of EitherT


Suppose I have the following:

val ints: Seq[Int] = ???
def foo(i: Int): EitherT[Future, Error, Seq[String]] = ???

I want to invoke the foo with the ints and accumulate Seq[String] result to eventually return EitherT[Future, Error, Seq[String]].

ints.map(i => foo(i))

Obviously the above returns Seq[EitherT[Future, Error, Seq[String]]] and that's not I want. When the foo returns Error for the first time in the map, I want to stop traversing and return the error.

What is the right way to achieve my goal?


Solution

  • ints.map(foo).reduce(for { a <- _ ; b <- _ } yield a ++ b)
    

    This basically does what you want, but I don't think it exactly fits the bill for this sentence:

    When the foo returns Error for the first time in the map, I want to stop traversing and return the error.

    The issue is that you need to traverse the seq before any of the futures complete, so you don't know if they return errors yet. You could "block" one by one and not make the next call to foo until the previous one completes, but then you don't get any parallelism. In theory it might be possible to start all of these futures and then cancel the still-running ones when one returns an error, but cancelling futures is not something that's naturally easy, unfortunately.