5

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)?

Mikel San Vicente
  • 3,831
  • 2
  • 21
  • 39

1 Answers1

7

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
}
Yuval Itzchakov
  • 146,575
  • 32
  • 257
  • 321