Future [Either [A, B]] into the future [Either [A, C]] using the function (B => Future [C])

I have Future[Either[A, B]] and a function providing Future[C] from B

I need to convert Future[Either[A, B]] to Future[Either[A, C]] .

Is there a direct way to get Future[Either[A, C]] and not Future[Either[A, Future[C]]] ?

I am thinking of something like:

 val eventuallyInitialValue: Future[Either[A, B]] = ??? val result: Future[Either[A, C]] = for { e: Either[A, B] <- initialValue c: C <- service.getValue(e.right) } yield e.right.map(_ => c) 

This is just pseudo code, since service.getValue(e.right) does not compile. What would be the right way to do this?

+5
source share
4 answers

Here is what I came up with:

 type B = Int type A = String type C = Long val eitherF: Future[Either[A, B]] = ??? def f(b: B): Future[C] = ??? val mapped: Future[Either[A, C]] = eitherF.flatMap { case Left(a) => Future.successful(Left(a)) case Right(b) => f(b).map(Right(_)) } 

Basically, you can flatMap future, and then, if it remains, just return success, if it is right, you can apply the future and map it to Right .

+7
source

Here's the scalaz solution. Please note that it uses the scalaz version.

 class A class B class C val initial: Future[A \/ B] = (new B).right.point[Future] val f: B => Future[C] = _ => (new C).point[Future] val result: Future[A \/ C] = (for { e <- EitherT(initial) res <- EitherT(f(e).map(_.right)) } yield res).run 

This is basically the same as @Ende Neu, but the match and reinstall are hidden in the monad transformer.

+6
source

You can do this by raising the function B => Future[C] to the function Either[E, B] => Future[Either[E, C]] , and then you can flatMap in the original future.

 eventuallyInitialValue.flatMap { case Left(e) => Future.successful(Left(e)) case Right(r) => bToFC(r).map(Right.apply _) } 
+3
source

Cats currently have an open delete request to add the semiflatMap method to OptionT and XorT , which accepts the function B => F[C] .

We could create a similar function for scalaz.EitherT :

 import scalaz._, Scalaz._ def semiFlatMap[F[_]: Monad, A, B, C](e: EitherT[F, A, B])(f: B => F[C]): EitherT[F, A, C] = e.flatMap(f andThen EitherT.right[F, A, C]) 

Then you could do:

 import scala.concurrent.Future import scala.concurrent.ExecutionContext.Implicits.global val futureEither: Future[Either[String, Int]] = Future.successful(Right(1)) val f: Int => Future[Long] = i => Future.successful(i + 1L) val appliedF: EitherT[Future,String,Long] = semiFlatMap(EitherT.fromEither(futureEither))(f) val futureEither2: Future[Either[String, Long]] = appliedF.run.map(_.toEither) 
+1
source

All Articles