繁体   English   中英

Haskell,实现 Monoids。 什么是 Semigroup,为什么它表现得如此怪异?

[英]Haskell, implementing Monoids. What is Semigroup and why does it act so weird?

我想实现一个名为 ComplexNumber 的自定义数据类型,如下所示: data ComplexNumber a = C (a,a)

现在我想实现 Monoid 变量并定义二进制 mempty Element 和 mappend ,如下所示:

instance Num a => Monoid (ComplexNumber a) where
    mempty = C (0,0)
    mappend = (C (a1, b1)) (C (a2, b2)) = C (a1 + a2, b1 + b2)

但这并没有成功,因此试图找出原因并遇到了 Semigroup(我仍然不太了解)并得出了一个至少可以编译并且似乎可以使用的解决方案:

instance Num a => Semigroup (ComplexNumber a) where
    (C (a1, b1)) <> (C (a2,b2)) = C (a1 + a2, b1 + b2)

instance Num a => Monoid (ComplexNumber a) where
    mempty = C (0,0)

有趣的是,当我删除 Semigroup 的实现时,程序不再编译并给我以下错误:

    * Could not deduce (Semigroup (ComplexNumber a))
        arising from the superclasses of an instance declaration
      from the context: Num a
        bound by the instance declaration at Aufgabe_10.hs:9:10-42
    * In the instance declaration for `Monoid (ComplexNumber a)'
  |
9 | instance Num a => Monoid (ComplexNumber a) where
  |  

为什么我可以将这两个部分编译在一起,但是当我删除半组时会发生错误? 特别是这个半群的东西

Semigroup只是具有<>操作实现的所有类型的 class,以某种方式使其具有关联性(即a<>(b<>c) ≡ (a<>b)<>c ,它确实如果我们忽略小的浮点偏差,则适用于您的复数)。

Monoid是半群的 class ,它们还具有中性元素mempty ,即始终满足mempty <> a ≡ a <> mempty ≡ a的元素(对于具有加法和零的复数也是如此)。
对于甚至没有<>操作的类型,即没有Semigroup实例,这将是一个荒谬的要求。 这由Semigroup表示为Monoid超类,因此不可能有一个类型是Monoid的实例而不是Semigroup的实例。

从历史上看, SemigroupMonoid是独立的类,旧的Monoid提供自己的mappend操作,相当于现代的<> 一些较旧的书籍/教程仍然基于这个旧的 class 层次结构。
但是因为有一堆类型只是半群而不是幺半群,所以 class 层次结构发生了变化。

一个幺半群[wiki]是一个具有恒等式的半群[wiki] :它有一个恒等元素 e [wiki] ,对于集合中的所有元素x ,关联二元运算x ⊕ e = e ⊕ x = x 因此,每个幺半群都是一个半群,因为半群是一个具有关联二元算子的代数结构,因此除了不需要单位元e之外,它的性质与幺半群中的相同。

base-4.9.0.0开始,引入了Semigroup class ,但随后SemigroupMonoid并没有“生活在一起”。 由于为Semigroup定义与Monoid实例不同的二元运算符没有多大意义(因为这可能会引起混淆),因为base-4.11.0.0SemigroupMonoid超类 事实上, Monoid被定义为[src]

  class半群 a => Monoid a where # ...

这意味着为了使某物成为Monoid的实例,它也必须是Semigroup的实例。 mappend:: Monoid a => a -> a -> a将自动链接到(<>):: Semigroup a => a -> a -> a Semigroup a => a -> a -> a 的实现,并且很可能最终会被删除。

因此,您不能再定义Monoid的实例而不定义Semigroup的实例。 但是您可以“机械地”从Monoid的旧实例创建一个实例,因为您只需将mappend的实现从Monoid实例移动到Semigroup的实例。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM