I want to create a Future of type Future[(Class1,Class2,Class3)]
from below code. However the only way I have found to do this is by using zip(). I find the solution ugly and properly not optimal. Can anybody enlightened me.
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)]
I have also tried to use Future.sequence(List(f0, f1, f2))
but this will not work as the new Future will have type of Future[List[U]]
where U
is the lub of Class1/2/3
whereas I want a 3-tuple preserving the original types
The most general form of registering a callback is by using the onComplete method, which takes a callback function of type Try[T] => U . The callback is applied to the value of type Success[T] if the future completes successfully, or to a value of type Failure[T] otherwise.
NOTE: With Future. onComplete() we are no longer blocking for the result from the Future but instead we will receive a callback for either a Success or a Failure.
sequence takes a list of futures and transforms it into a single future of list in an asynchronous manner. For instance, assume that you have a list of independent jobs to be run simultaneously. In such a case, the list of futures can be composed into a single future of list using Future. sequence.
Future represents a result of an asynchronous computation that may or may not be available yet. When we create a new Future, Scala spawns a new thread and executes its code. Once the execution is finished, the result of the computation (value or exception) will be assigned to the Future.
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)
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
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.
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 }
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With