【问题标题】:Monads VS Applicative functors for FuturesMonads VS Applicative functors for Futures
【发布时间】:2016-05-10 13:47:17
【问题描述】:

假设我想汇总来自 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)

不过,这种区别对我来说有点太隐晦了,可能有人一开始没有注意到。


Applicatives 也能解决问题

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

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

【问题讨论】:

  • 我认为,从根本上说,如果您需要 someComputationA 的输出来计算 someComputationB 的输出,则可以使用 monad。如果你只想计算两个独立的东西并将它们组合起来,applicative 就可以了。虽然这并不是关于应用程序的特别“并行”,但我认为由于上述原因,monads 本质上是顺序的。如果您需要真正的并行计算,monad 可能不是您正在寻找的结构。 挥手
  • 我的回答here有一些相关的讨论。
  • 并行运行Future 计算的标准习惯用法是zip: for ((user, data) &lt;- loadUser zip loadData) yield Payload(user, data)
  • 你可能会发现这个discussion很有用。

标签: scala monads scalaz applicative scala-cats


【解决方案1】:

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

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

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

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

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

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

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

不过,zipping more than 2 futures 似乎没有那么优雅。

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

【讨论】:

    猜你喜欢
    • 2020-06-16
    • 1970-01-01
    • 2023-03-04
    • 1970-01-01
    • 2015-12-30
    • 2011-05-20
    • 1970-01-01
    • 1970-01-01
    • 2023-03-17
    相关资源
    最近更新 更多