首页 > 解决方案 > Haskell 中的 pure 和 mempty 有什么区别?

问题描述

在学校,我的任务是编写一个函数,将数字附加到列表的左侧,如果它们是偶数的话。类型签名如下:

appendIfEven :: (Applicative f, Monoid (f a), Integral a) => a -> f a -> f a

我的答案是以下代码

appendIfEven :: (Applicative f, Monoid (f a), Integral a) => a -> f a -> f a
appendIfEven x ms = if x `mod` 2 == 0 then mempty x `mappend` ms else ms

Haskell 可以编译我的代码,但不能正常工作。经过一些实验,我将mempty切换为pure

appendIfEven :: (Applicative f, Monoid (f a), Integral a) => a -> f a -> f a
appendIfEven x ms = if x `mod` 2 == 0 then pure x `mappend` ms else ms

哪个工作得很好。但为什么 ?不应该pure == mempty吗?(在这种情况下)这对我的导师来说似乎并不重要。但是我真的很想了解更多关于 Haskell 以及我错在哪里......

标签: haskellapplicativemonoids

解决方案


你无意中使用了一个意想不到的幺半群,它顺便让你的代码编译了。

当您编写mempty x `mappend` ms时,该ms值具有 type f a,这是一个幺半群。这强制mempty x具有相同的类型,因为mappend需要两个相同类型的参数。因此我们必须有

mempty x :: f a

这意味着,因为x :: a

mempty :: a -> f a

很奇怪,对吧?

好吧,库中恰好有一个实例

instance Monoid t => Monoid (u -> t) where
   mempty = \_ -> mempty
   ...

您无意中使用了传递xmempty, 因为t可以是f a, 并且u可以a在上面的实例中。Haskell 解决了幺半群约束以便使用这个实例。

这也意味着

mempty x `mappend` ms

是相同的

(\_ -> mempty) x `mappend` ms  -- this is the mempty for (f a), instead!

这与

mempty `mappend` ms   -- this is the mempty for (f a), instead!

这与

ms

因此,您的代码完全忽略了该x参数。

相比之下,在一般情况下pure x确实取决于x,因此最终结果可能会非常不同。


推荐阅读