类型函数式编程中的模式选项[Future [Int]]转换为Future [Option [Int]]

时间:2016-10-12 10:18:59

标签: scala monads monad-transformers

我在Scala中发现myselfe的常见情况如下:

  1. 阅读一些返回Option
  2. 的道具
  3. 使用Future
  4. 中的道具
  5. 对将来返回Option
  6. 的结果进行一些转换

    这会产生Option[Future[Option[_]]]这样的类型,更好的解决方案是使用Future[Option[Option[_]]]之类的转换,例如使用下面的内容:

    def transform[A](o: Option[Future[A]]): Future[Option[A]] =
      o.map(f => f.map(Option(_))).getOrElse(Future.successful(None))
    

    (代码从here被盗)

    然后,我可以使用OptionsFuture内使用任意数量的flatmap

    这似乎是一种常见的模式,我确信它可以在某种意识形态的方式中在Scala中使用,而不必一遍又一遍地实现变换方法。

    所以我的问题是:如上例所示,将Option[Future[Option[_]]]改为外部的最理想方式是什么?

3 个答案:

答案 0 :(得分:1)

cat库中的Traverse类型类可能对此有所帮助。它可以处理将Option[Future[Something]]转换为Future[Option[Something]]

的样板

使用Ammonite REPL的例子:

$ amm
Loading...
Welcome to the Ammonite Repl 0.7.7
(Scala 2.11.8 Java 1.8.0_101)
@ import $ivy.`org.typelevel::cats-core:0.7.2`
import $ivy.$

首先是一些进口......

@ import cats.Traverse
import cats.Traverse
@ import cats.implicits._
import cats.implicits._
@ import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.ExecutionContext.Implicits.global
@ import scala.concurrent.Future
import scala.concurrent.Future

这是我们想要改变的事情:

@ val optionOfFuture: Option[Future[String]] = Some(Future.successful("hello"))
optionOfFuture: Option[Future[String]] = Some(scala.concurrent.impl.Promise$KeptPromise@43ac3b45)

我们使用Traverse的{​​{1}}方法切换sequenceOption

Future

或者如果您更喜欢语法加糖版本:

@ val futureOfOption: Future[Option[String]] = Traverse[Option].sequence(optionOfFuture)
futureOfOption: Future[Option[String]] = Success(Some(hello))

有关@ import cats.syntax.traverse._ import cats.syntax.traverse._ @ val futureOfOption2: Future[Option[String]] = optionOfFuture.sequence futureOfOption2: Future[Option[String]] = Success(Some(hello)) 可以执行的操作的更多信息,请查看cats documentation

答案 1 :(得分:1)

我认为,问题在于你的问题是#3:为什么"结果的某些转换",操纵Future会返回Option?闻起来有点不对劲。只是让他们首先返回Future,你就不会遇到这个问题。

顺便说一句,我不确定你的意思是什么"能够使用flatMap"来处理任意数量的选项,但几乎肯定是错的:flatMap将帮助您在地图时删除 1 额外级别的选项Some(Some("foo")).flatMap(x => Some(s))会产生Some(Some("foo")).flatten明确地做了同样的事情: Some(Some(Some("foo"))).flatten会产生Some(Some("foo")),而不是Some("foo")"foo",正如您所期望的那样。

请注意,在每种情况下,只有一个级别的选项,展平处理,而不是"任意数字"。 通常的做法是在遇到它们时摆脱额外的选项(立即变平以永远拥有Future[Option[T]]而不是Future[Option[Option[T]]])。

答案 2 :(得分:0)

val a: Option[Future[Option[T]]] = ...

val b: Future[Option[T]] = a.getOrElse(Future(None))