2016-06-24 48 views
5

我有Future[Either[A, B]],并且函数B提供Future[C]使用(B => Future [C])函数Future [[A,B]]到将来[要么[A,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)只是伪代码不能编译。什么是正确的做法?

回答

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它。

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 _) 
} 
+0

感谢。它只是需要返回作为一个右:bToFC(r).map(右(_)) –

+0

@Alban:是的,编辑在 – Daenyth

+0

如果您使用'Future.successful'而不是'Future.apply'您将避免在线程池上创建'Left(e)'。 –

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变压器中。

+0

'initial.flatMap(_。fold(identity,(Right.apply _)compose f)'' – Daenyth

+0

它不会更简单吗?它不会为我编译,我不确定它是否可以工作,但如果它看起来很有趣,也许你应该把它作为答案 –

+0

你是对的,类型是错误的;你需要在'f'的结果上映射'Right', – Daenyth

1

猫目前有an open pull request的方法semiflatMap添加OptionTXorT这需要一个函数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) 
相关问题