Flattening Future[EitherT[Future, A, B]]

676 Views Asked by At

As the title mentions.

Having many operations done using EitherT[Future, A, B]. Sometimes I want map left or right through another operation having signature A => Future[C]. Other scenario is that EitherT[Future, A, B] the result of a mapping over a future resulting Future[EitherT[Future, A, B]].

How can I elegantly flatten types like:

EitherT[Future, Future[A], Future[B]] and Future[EitherT[Future, A, B]]

Thank you in advance.

1

There are 1 best solutions below

0
On BEST ANSWER

In all your cases you can use EitherT#flatMap (or EitherT#flatMapF), in combination with lifting some value to EitherT (or disjunction (\/) with flatMapF).

  • Mapping a B => F[C] over an EitherT[F, A, B] :

    flatMap + lift

    import scala.concurrent.Future
    import scala.concurrent.ExecutionContext.Implicits.global
    
    import scalaz._, Scalaz._
    
    def f(i: Int): Future[Double] = Future.successful(i.toDouble)
    val r = EitherT.right[Future, String, Int](Future.successful(1))
    
    r.flatMap(i => EitherT.right(f(i)))
    // or
    r.flatMapF(i => f(i).map(_.right))
    
  • Mapping a A => F[C] over an EitherT[F, A, B] :

    swap + flatMap + lift

    def g(s: String): Future[Int] = Future.successful(s.length)
    
    val l = EitherT.left[Future, String, Int](Future.successful("error"))
    
    l.swap.flatMap(s => EitherT.right(g(s))).swap
    // or
    l.swap.flatMap(s => EitherT.left[Future, Int, Int](g(s)))
    // or
    l.swap.flatMapF(s => g(s).map(_.left))
    
  • Mapping an A => Either[F, B, C] to an F[A] :

    lift + flatMap

    def h(i: Int): EitherT[Future, String, Int] = 
      EitherT.right(Future.successful(i + 1))
    
    val fut = Future.successful(1)
    
    // mapping gives us Future[EitherT[Future, String, Int]]
    fut.map(h)                    
    
    // lifting to EitherT and flatMap gives us EitherT[Future, String, Int]
    EitherT.right(fut).flatMap(h)