Nested For Comprehensions with Futures

2019-08-06 17:12发布

问题:

Given:

import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global

def f: Future[Either[String, Int]] = Future { Right(100)}

def plus10(x: Int): Future[Either[String, Int]] = 
    Future { Right(x + 10) }

I'm trying to chain the Future[...] together as so:

scala> for { 
     |  x <- f
     |  y <- for { a <- x.right } yield plus10(a)
     | } yield y
<console>:17: error: value map is not a member of Product with 
    Serializable with 
   scala.util.Either[String,scala.concurrent.Future[Either[String,Int]]]
        y <- for { a <- x.right } yield plus10(a)
                     ^

I am expecting to get: Future{Right(100)} as a result, but I get the above compile-time error.

Travis Brown gave an excellent answer on how to use Monad Transformers to fix my code here. However, how can I fix my code without Monad Transformers?

回答1:

Turns out that I can use Either#fold:

 scala> for { 
     |  a <- f
     |  b <- a.fold(_ => Future { Left("bad") }, xx => plus10(xx) )
     | } yield b
res16: scala.concurrent.Future[Either[String,Int]] = 
     scala.concurrent.impl.Promise$DefaultPromise@67fc2aad

scala> res16.value
res17: Option[scala.util.Try[Either[String,Int]]] = 
          Some(Success(Right(110)))


回答2:

I was about to answer when yours appeared, but you might still look at this:

val res = for {
  x <- f
  y <- x.fold(x => Future{Left(x)}, plus10)
} yield y

It is a little more concise on the right side and keeps the left side.



标签: scala