3

这是 Haskell 中的幺半群示例:

> import Data.Monoid
> Sum 5 <> Sum 6 <> Sum 10
Sum {getSum = 21}
> mconcat [Sum 5, Sum 6, Sum 10]
Sum {getSum = 21}
> getSum $ mconcat $ map Sum [5, 6, 10]
21
> getProduct $ mconcat $ map Product [5, 6, 10]
300

这是 Clojure 中的幺半群示例:

(defn plus-monoid
    ([]
        0)
    ([a b]
        (+ a b)))

(plus-monoid) 

(plus-monoid 3 4)

(reduce plus-monoid [2 3 4]) 

这是 Haskell 中的环示例:

module Rings where

newtype Matrix r = M [[r]] deriving (Eq,Show)

instance Num r => Num (Matrix r) where
   M [[a,b],[c,d]] + M [[a',b'],[c',d']] = M [[a+a',b+b'],[c+c',d+d']]
   negate (M [[a,b],[c,d]]) = M [[-a,-b],[-c,-d]]
   M [[a,b],[c,d]] * M [[e,f],[g,h]] = M [[a*e+b*g, a*f+b*h] ,[c*e+d*g, c*f+d*h]]
   fromInteger n = M [[fromInteger n, 0],[0, fromInteger n]]

> M [[1,2],[3,4]] - M [[1,0],[0,1]]
M [[0,2],[3,3]]
> M [[2,0],[0,3]] * M [[1,2],[3,4]]
M [[2,4],[9,12]]

这是基于此的 Clojure 中的环示例:

(defprotocol ring
  (plus [x y])
  (mult [x y])
  (neg [x])
  (zero [])
  (one []) )

似乎 - (借用 Java 用语)环和幺半群之间的区别在于环具有“要实现的接口上的附加方法”。(也许我错了)。现在对我来说,这会对关联性产生影响——但我还没有完全理解这一点。

我的问题是:幺半群和环之间的差异意味着什么?

4

2 回答 2

10

额外的方法是必要的,但不足以制作戒指。环形结构是由管理方法行为及其交互的规则产生的。

例如,您可以实例化 Monad 并实施绑定和返回,公然无视 Monad 法则,只要您选择正确的类型,Haskell 的类型检查器就会很高兴。称它为 Monad 并不能使它表现得像 Monad 应该的那样。

戒指也是如此。

特别是,如果您调用环的合同方法+ plus, - neg, * mul, 0 zero,1 one那么

  • +, 0并且*, 1应该遵守幺半群定律。
  • -应该在下提供逆+,即-a + a = 0
  • +应该通勤,即a + b = b + a
  • *应该分布在+,即
    a * (b + c) = (a * b) + (a * c) (b + c) * a = (b * a) + (c * a)

如果您还需要*通勤并有逆向,那么您将拥有一个字段。

于 2014-03-01T05:34:13.943 回答
3

我可以更轻松地回答这个问题,将幺半群与半环进行比较(即像环,但没有否定)。

Monoid理解半环最简单的方法是,当一个类型有两个以特定方式相互交互的有效实例时,它们最常出现。与其定义两个单独的新类型(每个Monoid实例一个),使用半环操作来区分我们指的是哪个实例要容易得多Monoid

这方面的一个例子是BoolHaskell 中的类型,它有两个有效Monoid的实例,我们使用 theAnyAllnewtypes 来区分:

newtype Any = Any { getAny :: Bool }
newtype All = All { getAll :: Bool }

instance Monoid Any where
    mempty = Any False
    (Any b1) `mappend` (Any b2) = Any (b1 || b2)

instance Monoid Any where
    mempty = And True
    (And b1) `mappend` (And b2) = And (b1 && b2)

Any使用/新类型来消除这两个实例的歧义是一件很痛苦的All事情,但是如果我们使用半环,那么我们可以通过使用0/(+)对应于其中一个Monoid实例(在这种情况下Any)和1/(*)对应于其他Monoid实例(在这种情况下And):

instance Num Bool where
    fromIntegral 0 = False
    fromIntegral 1 = True

    (+) = (||)
    (*) = (&&)

Monoid两个竞争实例的另一个示例是Sums 和Products 表示数字:

newtype Sum     a = Sum     { getSum     :: a }
newtype Product a = Product { getProduct :: a }

instance Num a => Monoid (Sum a) where
    mempty = Sum 0
    (Sum x) `mappend` (Sum y) = Sum (x + y)

instance Num a => Product (Product a) where
    mempty = Product 1
    (Product x) `mappend` (Product y) = Product (x * y)

(+)通常,直接使用/(*)来消除Monoid我们所指的两个 s中的哪个更容易。

请注意,在这两种情况下(布尔值和数字),所Monoid讨论的两个实例以下列方式相互交互:

x * (y + z) = (x * y) + (x * z)

x * 0 = 0

这实际上是变相的函子定律的一个例子。如果你定义:

fmap = (x *)

(.) = (+)

id = 0

然后它和说的是一样的:

fmap (y . z) = fmap y . fmap z

fmap id = id

因此,您不一定要对实现两个单独Monoid实例的任何东西使用半环。您还想验证这两个Monoid实例是否也遵守分配/零定律(即函子定律)。

于 2014-03-01T05:42:51.177 回答