【问题标题】:Future[Either[A, B]] to Future[Either[A, C]] using a (B => Future[C]) functionFuture[Either[A, B]] 到 Future[Either[A, C]] 使用 (B => Future[C]) 函数
【发布时间】:2016-10-27 01:39:15
【问题描述】:

我有一个Future[Either[A, B]] 和一个从B 提供Future[C] 的函数。

我需要将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) 无法编译。正确的做法是什么?

【问题讨论】:

    标签: scala future either


    【解决方案1】:

    这是我想出的:

    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 映射到它。

    【讨论】:

      【解决方案2】:

      这是 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 转换器中。

      【讨论】:

      • initial.flatMap(_.fold(identity, (Right.apply _) compose f)不是更简单吗?
      • 它不能为我编译,我不确定它是否可以工作,但如果它看起来很有趣,也许你应该将它作为答案发布。
      • 你是对的,类型不对;您需要将Right 映射到f 的结果上
      【解决方案3】:

      您可以通过将B =&gt; Future[C] 函数提升为Either[E, B] =&gt; Future[Either[E, C]] 函数来做到这一点,然后您可以在原来的未来上使用flatMap

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

      【讨论】:

      • 谢谢。它只需要作为右返回:bToFC(r).map(Right(_))
      • 如果您使用Future.successful 而不是Future.apply,您将避免在线程池上创建Left(e)
      【解决方案4】:

      Cats 目前有 an open pull requestOptionTXorT 添加一个方法 semiflatMap 和一个函数 B =&gt; 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)
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2019-09-23
        • 1970-01-01
        • 2012-12-19
        • 2018-06-29
        • 2013-07-02
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多