如何在不使用zip()的情况下将不同类型的期货合并为一个Future

Pet*_*che 32 scala future akka applicative

我想Future[(Class1,Class2,Class3)]从下面的代码创建一个类型的Future .然而,我发现这样做的唯一方法是使用zip().我发现解决方案很难看,并且不是最佳的.任何人都可以开悟我.

val v = for (
    a <- {
        val f0:Future[Class1] = process1
        val f1:Future[Class2] = process2
        val f2:Future[Class3] = process3
        f0.zip(f1).zip(f2).map(x => (x._1._1,x._1._2,x._2))
    } yield a  // Future[(Class1,Class2,Class3)]
Run Code Online (Sandbox Code Playgroud)

我也曾尝试使用Future.sequence(List(f0, f1, f2)),但是这不会为新的未来的工作会有的类型Future[List[U]],其中U是的LUB Class1/2/3,而我希望有一个3元组保留原始类型

Vik*_*ang 49

val result: Future[(Class1, Class2, Class3)] = {
  val f1 = process1
  val f2 = process2
  val f3 = process3
  for { v1 <- f1; v2 <- f2; v3 <- f3 } yield (v1, v2, v3)
}
Run Code Online (Sandbox Code Playgroud)

  • 不,如果你将processX调用放在for-comprehension中,那将会使用flatMap.由于fX是Future,这意味着processX将启动计算并立即返回Future. (13认同)
  • 这不会导致计算顺序执行而不是并行执行吗? (2认同)
  • @Zennichimaro我在我的博客上描述了一些这些模式:http://viktorklang.com/blog/ (2认同)

oxb*_*kes 35

应用函数

你要求的是一个未来的应用函子.请参阅scalaz Applicative Builder模式.在你的背后滚动你自己应该是​​相当微不足道的zip

(f0 |@| f1 |@| f2)(g) //g is function (Class1, Class2, Class3) => Z
Run Code Online (Sandbox Code Playgroud)

这相当于直接适用:

(f0 <***> (f1, f2))(g)
Run Code Online (Sandbox Code Playgroud)

Scalaz附带一个香蕉括号方法,它从目标和参数(即你要求的)形成一个元组.所以你的解决方案将是:

f0 <|**|> (f1, f2) //that. is. all.
Run Code Online (Sandbox Code Playgroud)

您可以通过为以下类型类定义类型类实例来获得所有这些:

trait Apply[Z[_]] {
  def apply[A, B](f: Z[A => B], a: Z[A]): Z[B]
}
Run Code Online (Sandbox Code Playgroud)

所以对于未来,这看起来像:

implicit val FutureApply = new Apply[Future] {
  def apply[A, B](f: Future[A => B], a: Future[A]): Future[B] = 
    (f zip a) map { case (fn, a1) => fn(a1) }
  }
}
Run Code Online (Sandbox Code Playgroud)

(实际上你也需要Pure和你Functor一样.Bind当你在它的时候也可以实施- 见附录)

关于这种模式的好处是你将开始在任何地方看到它(例如in Option,in Validation,in List等).例如,2个流的笛卡尔积是:

s1 <|*|> s2
Run Code Online (Sandbox Code Playgroud)

笔记

以上所有假设scalaz 6,毫无疑问scalaz 7 for 2.10默认会附带这些类型类.PurePointed在scalaz7中重命名.


附录

未来的其他类型类实例:

implicit val FuturePure = new Pure[Future] {
  def pure[A](a: =>A): Future[A] = Future { a }
}
implicit val FutureBind = new Bind[Future] {
  def bind[A, B](a: Future[A], f: A => Future[B]): Future[B] = a flatMap f
}
implicit val FutureFunctor = new Functor[Future] {
  def map[A, B](a: Future[A], f: A => B): Future[B] = a map f
}
Run Code Online (Sandbox Code Playgroud)