我不知道如何描述这个问题,所以我只会显示类型签名。
我有以下实例:
val x:Future[F[Future[F[B]]]] = ???
我想要一个例子:
val y:Future[F[B]] = ???
F
是Monad,所以我有以下方法:
def pure[A](a:A):F[A] = ???
def flatMap[A, B](fa:F[A], f:A => F[B]):F[B] = ???
def map[A, B](fa:F[A], f:A => B):F[B] = flatMap(fa, (a:A) => pure(f(a)))
我认为以下内容应该有效,但感觉不对:
x.flatMap { fWithFuture =>
val p = Promise[F[B]]
flatMap(fWithFuture, (futureF: Future[F[B]]) => {
p.completeWith(futureF)
pure(())
})
p.future
}
我缺少一个概念吗?
一些背景信息。我试图定义这样的函数:
def flatMap[A, B](fa:Future[F[A]], f: A => Future[F[B]]):Future[F[B]] = ???
也许这在概念上是一件奇怪的事情。欢迎任何关于有用抽象的提示。
正如Rex Kerr在上面指出的那样,你经常可以使用monad变换器来处理你发现自己有像这样的交替层的情况。例如,如果 F
这是 Option
,你可以使用 Scalaz 7.1的 OptionT
monad变压器写你的 flatMap
:
import scalaz._, Scalaz._
type F[A] = Option[A]
def flatMap[A, B](fa: Future[F[A]], f: A => Future[F[B]]): Future[F[B]] =
OptionT(fa).flatMap(f andThen OptionT.apply).run
OptionT[Future, A]
这是一种包装 Future[Option[A]]
。如果你的 F
是 List
,只需更换 OptionT
同 ListT
和 run
同 underlying
(等等)。
好的是,当你和你一起工作时 OptionT[Future, A]
例如,你通常可以避免最终结果 Future[Option[Future[Option[A]]]]
首先 - 看我的答案 这里 进行更详细的讨论。
一个缺点是并非所有的monad都有变压器。例如,你可以把 Future
在堆栈的底部(正如我上面所做的那样),但是没有真正有用的定义方法 FutureT
。
这可能会回答“我想要一个实例:”部分。
$ scala
Welcome to Scala version 2.10.4 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_05).
Type in expressions to have them evaluated.
Type :help for more information.
scala> import scala.concurrent.Future
import scala.concurrent.Future
scala> import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.ExecutionContext.Implicits.global
scala> Future(List(Future(1),Future(2),Future(3))) // Future[F[Future[B]]]
res0: scala.concurrent.Future[List[scala.concurrent.Future[Int]]] = scala.concurrent.impl.Promise$DefaultPromise@41ab013
scala> res0.map(Future.sequence(_)) // transformed to Future[Future[F[B]]
res1: scala.concurrent.Future[scala.concurrent.Future[List[Int]]] = scala.concurrent.impl.Promise$DefaultPromise@26a4842b
scala> res1.flatMap(identity) // reduced to Future[F[B]]
res2: scala.concurrent.Future[List[Int]] = scala.concurrent.impl.Promise$DefaultPromise@4152d38d
希望下面的flatMap定义应该给出转换类型:)的想法
为了便于理解,我将F替换为List类型。
scala> def flatMap[A, B](fa:Future[List[A]], f: A => Future[List[B]]):Future[List[B]] = {
| val x: Future[List[Future[List[B]]]] = fa.map(_.map(f))
| val y: Future[Future[List[List[B]]]] = x.map(Future.sequence(_))
| val z: Future[Future[List[B]]] = y.map(_.map(_.flatten))
| z.flatMap(identity)
| }
flatMap: [A, B](fa: scala.concurrent.Future[List[A]], f: A => scala.concurrent.Future[List[B]])scala.concurrent.Future[List[B]]