什么时候应该使用 applicatives 而不是 monads?

PhD*_*PhD 4 monads haskell scala applicative

我一直在工作中使用 Scala,为了更深入地理解函数式编程,我选择了 Graham Hutton's Programming in Haskell(喜欢它:)

在关于 Monads 的章节中,我第一次看到了 Applicative Functors (AFs) 的概念

在我(有限的)专业 Scala 能力中,我从来不必使用 AF,并且总是编写使用 Monad 的代码。我试图提炼对“何时使用 AFs”的理解以及由此产生的问题。这种见解是否正确:

如果您的所有计算都是独立且可并行的(即,一个的结果不能确定另一个的输出),如果输出需要通过管道传输到没有影响的纯函数,AF 会更好地满足您的需求。但是,如果你有一个甚至单一依赖的AF不会帮助,你会被强制使用单子。如果需要将输出通过管道传输到具有效果的函数(例如,返回 Maybe),您将需要 Monads。

例如,如果你有这样的“monadic”代码:

val result = for {
 x <- callServiceX(...)
 y <- callServiceY(...) //not dependent on X 
} yield f(x,y)
Run Code Online (Sandbox Code Playgroud)

最好做一些类似的事情(scala 的伪 AF 语法,|@|就像并行/异步调用之间的分隔符)。

val result = (callServiceX(...) |@| callServiceY(...)).f(_,_)

Run Code Online (Sandbox Code Playgroud)
  • 如果f == pure and callService* are independentAF 可以更好地为您服务
  • 如果f有效果,即,f(x,y): Option[Response]您将需要 Monads
  • 如果callServiceX(...), y <- callServiceY(...), callServiceZ(y)即,链中甚至只有一个依赖项,请使用 Monads。

我的理解正确吗?我知道 AFs/Monads 有很多,而且我相信我了解其中一个的优势(在大多数情况下)。我想知道的是决定在特定上下文中使用哪个的决策过程。

luq*_*qui 5

这里没有真正的决定:总是使用 Applicative 接口,除非它太弱。1

这是抽象强度的本质张力:更多的计算可以用 Monad 表达;用 Applicative 表示的计算可以以更多方式使用。

关于需要使用 Monad 的条件,您似乎大部分是正确的。我不确定这个:

  • 如果f有效果,即f(x,y) : Option[Response]你需要 Monads。

不必要。这里讨论的函子是什么?没有什么可以阻止您创建F[Option[X]]ifF是应用程序。但就像以前一样,您将无法F根据是否Option成功做出进一步的决定——整个“调用树”的F动作必须在不计算任何值的情况下是可知的。


1 撇开可读性问题不谈,就是这样。由于其命令式外观,Monadic 代码可能更容易被传统背景的人所接受。