Ele*_*onk 8 monads scala future
我有一个表示DB记录的字符串ID列表.我想异步地从数据库加载它们,然后异步上传每个记录到远程服务器,然后当完成所有记录上传后,记录上传的记录的ID.
由于我使用的是Scala 2.9.2,我使用的是Twitter的core-util Future实现,但它应该与Monadic转换的2.10期货完全一样.
一般概念是这样的:
def fetch(id: String): Future[Option[Record]]
def upload(record: Record): Future[String]
def notifyUploaded(ids: Seq[String]): Unit
val ids: Seq[String] = ....
Run Code Online (Sandbox Code Playgroud)
我试图通过for comprehension来做到这一点,但fetch返回Future of Option这一事实使得它变得模糊不清并且代码无法编译:
for {
id <- ids
maybeRecord <- fetch(id)
record <- maybeRecord
uploadedId <- upload(record)
} yield uploadedId
Run Code Online (Sandbox Code Playgroud)
编译此结果会导致以下错误:
scala: type mismatch;
found : com.twitter.util.Future[String]
required: Option[?]
uploadedId <- upload(record)
^
Run Code Online (Sandbox Code Playgroud)
我错过了什么?为什么编译器期望uploadedId是一个选项?有什么好办法可以解决这个问题吗?
考虑flatMap(或绑定)函数的签名:
trait Monad[M[_]] {
def flatMap[A](a : M[A], f : A => M[B]) : M[B]
....
Run Code Online (Sandbox Code Playgroud)
在你的情况下,你试图使用flatMap一个Option,给它一个f生成一个Future.但正如在上面的签名中,f应该在同一个monad中生成一些它被调用的东西.
Scala在这方面不一定非常有用,因为它非常善于将事物转换Seq为(比如s),这样你就可以得到你可以将任意flatMap调用链接在一起的印象,无论容器如何.
你可能想要的是一个'Monad变换器',它可以让你有一些组合monad的能力.Debasish Ghosh有一篇关于在这里使用Scalaz monad变换器的帖子.