Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Future[Either[A, B]] to Future[Either[A, C]] using a (B => Future[C]) function

I've got a Future[Either[A, B]] and a function providing a Future[C] from a B.

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

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

I'm thinking about 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)

It's just pseudo-code since service.getValue(e.right) does not compile. What would be the correct way of doing it?

like image 413
Alban Dericbourg Avatar asked Jun 24 '16 12:06

Alban Dericbourg


3 Answers

This 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 the future and then if it's a left just return the success, if it's a right you can apply the future and map a Right to it.

like image 166
Ende Neu Avatar answered Nov 16 '22 18:11

Ende Neu


Here is scalaz solution. Note that it uses scalaz version of either.

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

It is basically the same what @Ende Neu did but the matching and rewrapping is hidden in monad transformer.

like image 6
Łukasz Avatar answered Nov 16 '22 16:11

Łukasz


You can do this by lifting the B => Future[C] function into an Either[E, B] => Future[Either[E, C]] function and then you can flatMap on the original future.

eventuallyInitialValue.flatMap {
  case Left(e) => Future.successful(Left(e))
  case Right(r) => bToFC(r).map(Right.apply _)
}
like image 3
Daenyth Avatar answered Nov 16 '22 18:11

Daenyth