Applicatives 中对 pure 的需求

The need for pure in Applicatives

我正在学习 Haskell 的应用程序。在我看来(我可能错了) pure 函数并不是真正需要的,例如:

pure (+) <*> [1,2,3] <*> [3,4,5]

可以写成

(+) <$> [1,2,3] <*> [3,4,5]

有人能解释一下 pure 函数相对于 fmap 显式映射的好处吗?

fmap 并不总能成功。具体来说,pure 可以让您在还没有 f 时引入它(其中 fApplicative)。一个很好的例子是

sequence :: Applicative f => [f a] -> f [a]

它采用 "actions" 生成值的列表并将其转换为生成值列表的操作。当列表中没有操作时会发生什么?唯一理智的结果是不产生​​任何值的操作:

sequence [] = pure [] -- no way to express this with an fmap
-- for completeness
sequence ((:) x xs) = (:) <$> x <*> sequence xs

如果您没有 pure,您将不得不要求一个非空的操作列表。你绝对可以让它工作,但这就像谈论加法而不提及 0 或乘法而不提及 1(正如其他人所说,因为 Applicatives 是幺半群)。您将反复 运行 进入边缘情况,这些情况可以用 pure 轻松解决,但必须通过对您的输入和其他创可贴的奇怪限制来解决。

我在这方面处于能力的边缘,所以不要把它看得太过分,但是评论有点太长了。

在类型 class 中包含 pure 可能有实际原因,但许多 Haskell 抽象是从理论基础派生的,我相信 Applicative 还有。正如文档所说,它是一个 strong lax monoidal functor(详见 https://cstheory.stackexchange.com/q/12412/56098)。我假设 pure 作为 身份 ,就像 returnMonad 所做的一样(这是类别中的 幺半群内函子).

考虑 pureliftA2:

pure :: a -> f a
liftA2 :: (a -> b -> c) -> f a -> f b -> f c

如果你稍微眯着眼,或许可以想象liftA2是一个二元运算,这也是文档中写的:

Lift a binary function to actions.

pure,那么,就是对应的恒等式。