Future[Either[A, B]] 到 Future[Either[A, C]] 使用 (B => Future[C]) 函数
Future[Either[A, B]] to Future[Either[A, C]] using a (B => Future[C]) function
我有一个 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)
无法编译。正确的做法是什么?
您可以通过将 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 _)
}
这是我想出的:
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
未来,然后如果它是左 return 成功,如果它是右你可以应用未来并将 Right
映射到它。
这里是 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 转换器中。
Cats 目前有 an open pull request 可以将方法 semiflatMap
添加到 OptionT
和 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)
我有一个 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)
无法编译。正确的做法是什么?
您可以通过将 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 _)
}
这是我想出的:
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
未来,然后如果它是左 return 成功,如果它是右你可以应用未来并将 Right
映射到它。
这里是 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 转换器中。
Cats 目前有 an open pull request 可以将方法 semiflatMap
添加到 OptionT
和 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)