Reputation: 1071
In the recursive recHelper
method below I need to return a list of Futures if all the elements returned Right
else a Future Left
. Problem is that I cannot concatenate the results. How to make this code work?
def either1 (i:Int): Future[Either[String,Int]] = Future {
if (i<3)
Right(i*2)
else
Left("error 1")
}
def either2 (i:Int): Future[Either[String,Int]] = Future {
if (i<3)
Right(i*2)
else
Left("error 2")
}
val seq = Seq (1,1,2,2)
def recHelper(remaining: List[Int]): Future[Either[String, Seq[Int]]] = {
remaining match {
case Nil => Nil
case h :: t => (if (h % 2 == 0) either1(h) else either2(h)).map {
headEither =>
headEither match {
case Left(s) => Future { Left(s) }
case Right(n) => Future { n :: recHelper(t) :: Nil } /// ERROR
}
}
}
}
recHelper(seq.toList)
Upvotes: 2
Views: 146
Reputation: 51271
An alternate solution:
def recHelper(remaining :Seq[Int]
,acc :Seq[Int] = Seq()
) :Future[Either[String, Seq[Int]]] = remaining match {
case Seq() => Future(Right(acc))
case h +: t => (if (h % 2 == 0) either1(h) else either2(h)).flatMap {
case Left(s) => Future(Left(s))
case Right(n) => recHelper(t, n +: acc)
}
}
recHelper(seq)
//res0: Future[Either[String,Seq[Int]]] = Future(Right(List(4, 4, 2, 2)))
Upvotes: 2
Reputation: 44918
The Nil => Nil
case indicates that you should read up again what the Future
and what the Either
monads do: Nil
is inferred to be of type List[Int]
. It's missing two applications of a monadic unit
, namely:
Right
to make it Either[List[Int]]
Future
, to make it Future[Either[List[Int]]
Same applies for the other cases. Here is a version that works:
import scala.concurrent._
import scala.util._
import scala.concurrent.ExecutionContext.Implicits.global
def either1(i: Int): Future[Either[String, Int]] = Future {
if (i<3) Right(i*2)
else Left("error 1")
}
def either2(i: Int): Future[Either[String, Int]] = Future {
if (i<3) Right(i*2)
else Left("error 2")
}
val seq = Seq(1, 1, 2, 2)
def recHelper(remaining: List[Int]): Future[Either[String, List[Int]]] = {
remaining match {
case Nil => Future { Right(Nil) }
case h :: t => for {
hEith <- (if (h % 2 == 0) either1(h) else either2(h))
res <- (hEith match {
case Left(s) => Future { Left(s) }
case Right(n) => for {
tEith <- recHelper(t)
} yield tEith.map(n :: _)
})
} yield res
}
}
recHelper(seq.toList)
You can't build a complex nested for-comprehension with two stacked monads by accident. I can only again strongly recommend to take a look at Scala Cats and EitherT
. They've build the monad transformer libraries not (only) for fun: it's actually quite painful to deal with two stacked monads simultaneously.
Upvotes: 2