32

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))たが、これは機能しません。元の型を保持する 3 タプルが必要なのに対し、新しい Futureは lub の型Future[List[U]]を持つためです。UClass1/2/3

4

4 に答える 4

51
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)
于 2012-06-22T14:47:18.737 に答える
35

アプリカティブ関手

あなたが求めているのは、未来のための適用可能な関手です。scalaz Applicative Builderパターンを参照してください。の裏に自分で転がすのはかなり簡単なはずです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) }
  }
}

(実際にはPureandFunctorも必要です。実行中に実装することもBindできます - 付録を参照してください)

このパターンの素晴らしい点は、どこでも見られるようになることです (たとえば、OptionValidationListなど)。たとえば、2 つのストリームのデカルト積は次のとおりです。

s1 <|*|> s2

ノート

上記のすべては scalaz 6 を想定していますが、おそらく 2.10 用の scalaz 7 にはデフォルトでこれらの型クラスが付属しています。scalaz7 で名前Pureが変更されました。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
}
于 2012-06-22T14:11:47.710 に答える
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")
于 2012-06-22T14:26:20.503 に答える