Search code examples
scalamonadsfor-comprehensionscala-2.12

For comprehensions Future and Either


I am struggling in how to compose a sequence of asynchronous processes in a nice monadic way. Each step of the process could fail so it is retrieving a Future[Either[String, T]].

def firstStep(input: Int): Future[Either[String, Long]] = ???
def secondStep(input: Long): Future[Either[String, String]] = ???
def thirdStep(input: String): Future[Either[String, Double]] = ???

Given these functions I would like to compose them like this

def process(input: Int): Future[Either[String Double]] = {
     for{
        res1 <- firstStep(input)
        res2 <- secondStep(res1)
        res3 <- thirdStep(res2)
     } yield res3
}

But this doesn't work because each partial result is an Either[String, T],and what I need is the T itself (or just stop the execution and return the Left if that's the case).

How can I compose this functions in a nice monadic way (using for-comprehensions)?


Solution

  • An EitherT monad transformer can help, either (pun intended) from cats or scalaz:

    import cats._
    import cats.implicits._
    import cats.EitherT
    
    def process(input: Int): Future[Either[String, Double]] = {
       val res = for {
          res1 <- EitherT(firstStep(input))
          res2 <- EitherT(secondStep(res1))
          res3 <- EitherT(thirdStep(res2))
       } yield res3
       res.value
    }