アプリカティブ関手
あなたが求めているのは、未来のための適用可能な関手です。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) }
}
}
(実際にはPure
andFunctor
も必要です。実行中に実装することもBind
できます - 付録を参照してください)
このパターンの素晴らしい点は、どこでも見られるようになることです (たとえば、Option
、Validation
、List
など)。たとえば、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
}