使用(B => Future [C])函数将来[[A,B]]到[未来[A,C]]

时间:2016-06-24 12:19:19

标签: scala future either

我有一个Future[Either[A, B]]和一个Future[C]来自B的函数。

我需要将Future[Either[A, B]]转换为Future[Either[A, C]]

是否可以直接获取Future[Either[A, C]]而不是Future[Either[A, Future[C]]]

我正在考虑类似的事情:

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)

这只是伪代码,因为service.getValue(e.right)无法编译。这样做的正确方法是什么?

4 个答案:

答案 0 :(得分:7)

这就是我提出的:

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(_))
}

基本上你可以flatMap未来然后如果它是左边只是返回成功,如果它是正确的你可以应用未来并将Right映射到它。

答案 1 :(得分:6)

这是scalaz解决方案。请注意,它使用scalaz版本。

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

它与@Ende Neu的基本相同,但匹配和重新包装隐藏在monad变换器中。

答案 2 :(得分:3)

您可以将B => Future[C]功能提升为Either[E, B] => Future[Either[E, C]]功能,然后flatMap原始未来。

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

答案 3 :(得分:1)

Cats目前有an open pull requestsemiflatMapOptionT添加方法XorT,其中包含B => F[C]函数。

我们可以为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])

然后你可以这样做:

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)