18

假设我想聚合来自 2 个远程服务的数据,并尽可能快地提供响应:

def loadUser: Future[User]
def loadData: Future[Data]

case class Payload(user: User, data: Data)

我知道这个按顺序执行异步任务:

for {
  user <- loadUser
  data <- loadData
} yield Payload(user,data)

虽然这是并行执行它们,因为异步任务在被顺序链接之前被触发:

val userF = loadUser
val dataF = loadData
for {
  user <- userF 
  data <- dataF
} yield Payload(user,data)

然而,这种差异对我来说有点太隐晦了,可能有人一开始并没有注意到它。


应用程序也解决了工作

(loadUser |@| loadData) { Payload(_,_) }

有人能告诉我我宁愿在应用程序和单子之间使用什么来执行并行异步计算吗?每种方法的优缺点是什么?

4

1 回答 1

15

所以,我正在回答我自己的问题,因为所有评论都链接到有用的资源。

特拉维斯布朗有一个很好的答案

使用最不强大的抽象来完成工作只是一种可靠的开发实践。原则上,这可能会实现原本不可能的优化,但更重要的是,它使我们编写的代码更具可重用性。

他还指出了一个有趣的事实:

遗憾的是,目前 Haskell 和 Scala 都使使用 monad 比使用应用函子更方便(在语法等方面)

Kolmar 指出可以压缩 2 个期货:

for ((user, data) <- loadUser zip loadData) yield Payload(user, data)

然而,压缩超过 2 个期货似乎并不那么优雅。

所以看起来 Applicative functor 最适合这项工作,但与 monad 相比,Scala 标准库并不鼓励我们使用它们,并且您需要一个额外的库,如 Scalaz 或 Cats

于 2016-02-02T09:49:17.677 回答