更新:您实际上可以在 Scalaz 7 中获得漂亮的 .sequence 语法而无需大惊小怪:
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.{ Future, future }
import scalaz._, Scalaz.{ ToTraverseOps => _, _ }
import scalaz.contrib.std._
val m = Map("a" -> future(1), "b" -> future(2), "c" -> future(3))
然后:
scala> m.sequence.onSuccess { case result => println(result) }
Map(a -> 1, b -> 2, c -> 3)
原则上没有必要像这样隐藏ToTraverseOps,但现在它可以解决问题。有关Traverse 类型类、依赖项等的更多详细信息,请参阅下面我的其余答案。
正如copumpkin 在上面的评论中指出的那样,Scalaz 包含一个Traverse type class 和一个Map[A, _] 的实例,这是这里的拼图之一。另一部分是Future 的Applicative 实例,它不在Scalaz 7 中(它仍然与pre-Future 2.9 交叉构建),但在scalaz-contrib 中。
import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.Future
import scalaz._, Scalaz._
import scalaz.contrib.std._
def sequence[A, B](m: Map[A, Future[B]]): Future[Map[A, B]] = {
type M[X] = Map[A, X]
(m: M[Future[B]]).sequence
}
或者:
def sequence[A, B](m: Map[A, Future[B]]): Future[Map[A, B]] =
Traverse[({ type L[X] = Map[A, X] })#L] sequence m
或者:
def sequence[A, B](m: Map[A, Future[B]]): Future[Map[A, B]] =
TraverseOpsUnapply(m).sequence
在一个完美的世界中,您可以编写 m.sequence,但是应该使这种语法成为可能的 TraverseOps 机器目前无法判断如何从特定的 Map 实例转到适当的Traverse 实例。