我想从下面的代码创建一个类型为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)]
我还尝试使用Future.sequence(List(f0, f1, f2))
,但这不起作用,因为新的Future将具有Future[List[U]]
类型,其中U
是Class1/2/3
的润滑,而我想要保留原始类型的3元组
答案 0 :(得分: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)
}
答案 1 :(得分:35)
您要求的是未来的应用函子。请参阅scalaz Applicative构建器模式。在zip
(f0 |@| f1 |@| f2)(g) //g is function (Class1, Class2, Class3) => Z
这相当于直接适用:
(f0 <***> (f1, f2))(g)
Scalaz附带一个香蕉括号方法,它从目标和参数(即你要求的)形成一个元组。所以你的解决方案将是:
f0 <|**|> (f1, f2) //that. is. all.
通过为以下类型类定义类型类实例,您可以完成所有这些:
trait Apply[Z[_]] {
def apply[A, B](f: Z[A => B], a: Z[A]): Z[B]
}
所以对于未来,这看起来像:
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) }
}
}
(实际上你也需要Pure
和Functor
。也可以在实施Bind
的同时实施 - 见附录)
这种模式的好处在于,您将开始在任何地方看到它(例如Option
,Validation
,List
等。例如,2个流的笛卡尔积是:
s1 <|*|> s2
以上所有假设scalaz 6,毫无疑问scalaz 7 for 2.10默认会附带这些类型类。 Pure
已在scalaz7中重命名为Pointed
。
未来的其他类型类实例:
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
}
答案 2 :(得分:3)
如果您正在使用akka查看数据流:http://doc.akka.io/docs/akka/2.0.2/scala/dataflow.html
你需要使用Delimited Continuations插件(但这很容易用sbt),然后就像:
val f:Future[(Class1,Class2,Class3)] = flow {
val f0 = process1
val f1 = process2
val f2 = process3
(f0(), f1(), f2())
}
应该编译。
build.sbt中的:
autoCompilerPlugins := true
addCompilerPlugin("org.scala-lang.plugins" % "continuations" % "2.9.1")
答案 3 :(得分:1)
你也可以使用猫:
import cats._
import cats.instances.future._
这样做的方法很少:
第一个更普遍的选择:
Applicative[Future].map3(f0, f1, f2){
(f0r, f1r, f2r) => //do something with results
}
and simpler :)&#39; ll只返回元组Future [(f0.type,f1.type,f2.type)
Applicative[Future].tuple3(f0, f1, f2)