选项[Future [Option [Int]]] =>未来[选项[INT]]

时间:2015-07-12 03:10:11

标签: scala

给出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)

我想要Future[Option[Int]]

我可以模式匹配(或使用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)))

但是,是否有更高阶的功能可以完成这项工作?

我想过使用sequence,但我没有外部类型List

> :t sequence
sequence :: Monad m => [m a] -> m [a]

1 个答案:

答案 0 :(得分:7)

Haskell的sequence并不像它可能那样通用,或者像Scalaz那样通用(我假设你提到sequence后你对Scalaz解决方案没问题。)

Scalaz的sequence(以及sequenceA中的Haskell Data.Traversable)只要求外部类型构造函数具有Traverse实例 - 它不一定必须是列表。 Option有一个Traverse个实例,因此sequence在这里工作得很好:

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还为orZero提供Option扩展方法,因为x.orZero的零为Future[Option[Int]],因此您只需编写Future(None)

我实际上可能会使用x.getOrElse(Future.successful(None)),但在这种情况下 - 它稍微(可能是无关紧要)更高效,但更重要的是它与Scalaz选项一样清晰,几乎同样简洁。