给出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]
答案 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选项一样清晰,几乎同样简洁。