【问题标题】:What is the difference between pure and mempty in Haskell?Haskell 中的 pure 和 mempty 有什么区别?
【发布时间】:2020-10-01 12:20:10
【问题描述】:

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

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 以及我错在哪里......

【问题讨论】:

  • 它们有不同的类型,其中之一。如果它们有不同的类型,它们怎么可能是一样的呢?
  • 它编译是因为a -> b 有一个Monoid 实例只要b 也是一个Monoid,在这种情况下mempty = const mempty
  • @user253751 a -> b 有一个Monoid 实例,在这种情况下mempty 本身也是一个函数。

标签: haskell applicative monoids


【解决方案1】:

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

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

mempty x :: f a

这意味着,因为x :: a

mempty :: a -> f a

很奇怪,对吧?

嗯,恰好库中有一个实例

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

您无意中使用了将x 传递给mempty,因为在上面的实例中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,因此最终结果可能会大不相同。

【讨论】:

    【解决方案2】:

    考虑将此应用于列表。

    mempty == []
    
    pure 5 = [5]
    

    那些看起来和我不太像。特别是,mempty x 应该是错误类型的。

    基本上mempty 给你一个empty 的东西,而pure x 给你一个带有x 的东西。

    【讨论】:

    • mempty 定义为 Monoid b => a -> bconst mempty
    • @chepner 是的,我感觉编译器不会抱怨,因为合适的实例要么确实存在,要么理论上可以存在。仍然不能使它成为一个明智的表达方式(除非你真的在使用这样的实例)。
    • 在适当的上下文中,使用mempty 作为函数是有意义的。相反,IMO,像mempty x 那样立即应用它是没有意义的,因为它等同于(在相同的上下文中)mempty
    • 函数实例使著名的技巧comparing snd <> comparing fst(f <> g) x y = (f x <> g x) y = f x y <> g x y成为可能。
    猜你喜欢
    • 2021-06-27
    • 1970-01-01
    • 2017-11-27
    • 1970-01-01
    • 2016-08-07
    • 2016-05-16
    • 1970-01-01
    • 2023-03-27
    • 2017-06-17
    相关资源
    最近更新 更多