Reputation: 41909
Given a Option[Future[Option[Int]]]
:
scala> val x: Option[Future[Option[Int]]] = Some ( Future ( Some ( 10 ) ) )
x: Option[scala.concurrent.Future[Option[Int]]] =
Some(scala.concurrent.impl.Promise$DefaultPromise@446a1e84)
I want Future[Option[Int]]
.
I can pattern match (or use Option#getOrElse
):
scala> x match {
| case Some(f) => f
| case None => Future { None }
| }
res6: scala.concurrent.Future[Option[Int]] =
scala.concurrent.impl.Promise$DefaultPromise@446a1e84
scala> res6.value
res7: Option[scala.util.Try[Option[Int]]] = Some(Success(Some(10)))
But, is there a higher-order function that will do the job?
I thought of using sequence
, but I don't have an outer type of List
:
> :t sequence
sequence :: Monad m => [m a] -> m [a]
Upvotes: 5
Views: 1407
Reputation: 139038
Haskell's sequence
isn't as generic as it could be, or as generic as Scalaz's (and I'm assuming you're okay with a Scalaz solution since you mention sequence
).
Scalaz's sequence
(and Haskell's sequenceA
in Data.Traversable
) only requires that the outer type constructor have a Traverse
instance—it doesn't necessarily have to be a list. Option
has a Traverse
instance, so sequence
will work just fine here:
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
import scalaz._, Scalaz._
def collapse(x: Option[Future[Option[Int]]]): Future[Option[Int]] =
x.sequence.map(_.flatten)
Scalaz also provides an orZero
extension method for Option
, which would allow you just to write x.orZero
, since the zero of Future[Option[Int]]
is Future(None)
.
I'd actually probably use x.getOrElse(Future.successful(None))
, though, in this case—it's slightly (probably irrelevantly) more performant, but more importantly it's as clear and almost as concise as the Scalaz options.
Upvotes: 8