Applicative Functors
What you are asking for is an applicative functor for a future. See scalaz Applicative Builder pattern. It should be rather trivial to roll your own on the back of zip
(f0 |@| f1 |@| f2)(g) //g is function (Class1, Class2, Class3) => Z
This is equivalent to the direct applicative:
(f0 <***> (f1, f2))(g)
Scalaz ships with a banana braces method which forms a tuple from the target and the arguments (i.e. what you asked for). So your solution will be:
f0 <|**|> (f1, f2) //that. is. all.
You get all this simply by defining a typeclass instance for the following typeclass:
trait Apply[Z[_]] {
def apply[A, B](f: Z[A => B], a: Z[A]): Z[B]
}
So for future this looks like:
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) }
}
}
(Actually you'd need Pure
and Functor
as well. Might as well implement Bind
whilst you're at it - see appendix)
The great thing about this pattern is that you will start to see it everywhere (e.g. in Option
, in Validation
, in List
etc). For example, the cartesian product of 2 streams is:
s1 <|*|> s2
Notes
All the above assuming scalaz 6, doubtless scalaz 7 for 2.10 will ship with these typeclasses by default. Pure
has been renamed Pointed
in scalaz7.
Appendix
Other type class instances for future:
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
}
f
of type(A, B, ...) => Z
and you want to lift it to a function of type(F[A], F[B], ...) => F[Z]
, you need applicative. In your case,f = (_, _, _)
andF = Future
. – Preclinical