簡體   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