Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Option[Future[Option[Int]]] => Future[Option[Int]]

Tags:

scala

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]
like image 250
Kevin Meredith Avatar asked Jul 12 '15 03:07

Kevin Meredith


1 Answers

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.

like image 89
Travis Brown Avatar answered Sep 22 '22 20:09

Travis Brown