Reputation: 8064
I have the following code
import scala.concurrent.{Future, Await}
import scala.concurrent.duration.Duration
import scala.concurrent.ExecutionContext.Implicits.global
def later(v: Int) = Future.successful(v)
val data = List(
(1, Some(1), Some(2)),
(2, Some(1), None),
(3, None, Some(2)),
(4, None, None)
)
def wait[T](v: Future[T]) = Await.result(v, Duration.Inf)
def seq[T](v: Option[Future[T]]): Future[Option[T]] = Future.sequence(v.toList).map(_.headOption)
def join[A, B](a: Option[Future[A]], b: Option[Future[B]]): Future[(Option[A], Option[B])] = seq(a).zip(seq(b))
wait(Future.sequence(data.map{ case (a, b, c) =>
join(b.map(later), c.map(later)).map((a, _))
})) == List(
(1, ((Some(1), Some(2)))),
(2, ((Some(1), None))),
(3, ((None, Some(2)))),
(4, ((None, None)))
)
I was wondering if there is any other way to write the join
function
Upvotes: 2
Views: 230
Reputation: 9820
If you are open to using Scalaz, you can omit the conversions between Option
and List
to be able to sequence
the two values.
import scala.concurrent.Future
import scala.concurrent.ExecutionContext.Implicits.global
import scalaz.std.option._
import scalaz.std.scalaFuture._
import scalaz.syntax.traverse._
def join[A, B](o1: Option[Future[A]], o2: Option[Future[B]]) =
o1.sequence zip o2.sequence
Upvotes: 3
Reputation: 16412
Without using other helper functions:
def join[A, B](a: Option[Future[A]], b: Option[Future[B]]): Future[(Option[A], Option[B])] =
(a, b) match {
case (Some(fa), Some(fb)) =>
for {
vfa <- fa
vfb <- fb
} yield Some(vfa) -> Some(vfb)
case (Some(fa), None) => fa map (Some(_) -> None)
case (None, Some(fb)) => fb map (None -> Some(_))
case _ => Future.successful(None -> None)
}
Upvotes: 0