EEC*_*LOR 11 monads functional-programming scala
我不知道如何描述这个问题,所以我只会显示类型签名.
我有以下实例:
val x:Future[F[Future[F[B]]]] = ???
Run Code Online (Sandbox Code Playgroud)
我想要一个例子:
val y:Future[F[B]] = ???
Run Code Online (Sandbox Code Playgroud)
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)))
Run Code Online (Sandbox Code Playgroud)
我认为以下内容应该有效,但感觉不对:
x.flatMap { fWithFuture =>
val p = Promise[F[B]]
flatMap(fWithFuture, (futureF: Future[F[B]]) => {
p.completeWith(futureF)
pure(())
})
p.future
}
Run Code Online (Sandbox Code Playgroud)
我缺少一个概念吗?
一些背景信息.我试图定义这样的函数:
def flatMap[A, B](fa:Future[F[A]], f: A => Future[F[B]]):Future[F[B]] = ???
Run Code Online (Sandbox Code Playgroud)
也许这在概念上是一件奇怪的事情.有关有用抽象的任何提示都是受欢迎的.
正如Rex Kerr在上面指出的那样,你经常可以使用monad变换器来处理你发现自己有像这样的交替层的情况.例如,如果F是Option,您可以使用Scalaz 7.1的OptionTmonad转换器来编写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
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
希望下面的 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]]
Run Code Online (Sandbox Code Playgroud)