akka 如何在不使用zip()的情况下将不同类型的Future组合成一个Future

jhkqcmku  于 2022-11-06  发布在  其他
关注(0)|答案(4)|浏览(161)

我想从下面的代码中创建一个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]]类型,其中UClass1/2/3的lub,而我想要一个保留原始类型的3元组

kxkpmulp

kxkpmulp1#

val result: Future[(Class1, Class2, Class3)] = for {
  _ <- Future.unit
  val f1 = process1
  val f2 = process2
  val f3 = process3
  v1 <- f1
  v2 <- f2
  v3 <- f3
} yield (v1, v2, v3)
cwtwac6a

cwtwac6a2#

适用函式

你所要求的是一个将来的应用函子。参见scalaz**Applicative Builder**pattern。在zip的后面滚动你自己的函子应该是相当简单的

(f0 |@| f1 |@| f2)(g) //g is function (Class1, Class2, Class3) => Z

这相当于直接适用格:

(f0 <***> (f1, f2))(g)

Scalaz附带了一个 banana braces 方法,该方法从目标和参数(即您所要求的)形成一个元组。因此,您的解决方案将是:

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) }
  }
}

(实际上,您还需要PureFunctor。您还可以实现Bind-请参阅附录)
这个模式的好处是你可以在任何地方看到它(例如,在Option,在Validation,在List等)。例如,两个流的笛卡尔积是:

s1 <|*|> s2

备注

  • 以上所有内容都假设scalaz 6,毫无疑问,2.10的scalaz 7默认情况下将附带这些类型类。Pure在scalaz 7中已被重命名为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
}
lfapxunr

lfapxunr3#

如果您使用的是akka,请查看数据流:http://doc.akka.io/docs/akka/2.0.2/scala/dataflow.html
您需要使用带分隔符的Continuations插件(但使用sbt很容易),然后类似于:

val f:Future[(Class1,Class2,Class3)] = flow {
  val f0 = process1
  val f1 = process2
  val f2 = process3
  (f0(), f1(), f2())
}

应编译。
在built.sbt中:

autoCompilerPlugins := true

addCompilerPlugin("org.scala-lang.plugins" % "continuations" % "2.9.1")
jgzswidk

jgzswidk4#

你也可以用猫:

import cats._
import cats.instances.future._

有几种有用的方法可以做到这一点:
第一个更通用的选项:

Applicative[Future].map3(f0, f1, f2){ 
  (f0r, f1r, f2r) => //do something with results
}

更简单:)它只返回元组Future[(f0.type,f1.type,f2.type)

Applicative[Future].tuple3(f0, f1, f2)

相关问题