幺半群和戒指之间差异的含义是什么?

时间:2014-03-01 04:59:48

标签: haskell clojure monoids

这是Haskell中monoid的一个例子:

> 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中monoid的一个例子:

(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 based on this中的一个响铃示例:

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

似乎是 - (借用Java的说法)difference between a ring and a monoid is that the ring在接口上有一个“附加方法来实现”。 (也许我错了)。现在对我来说,这会对相关性产生影响 - 但我并没有全神贯注于这一点。

我的问题是:幺半群与戒指之间的差异有何影响?

2 个答案:

答案 0 :(得分:10)

其他方法是必要的但不足以制作戒指。环结构由管理方法行为及其相互作用的规则产生。

例如,您可以实例Monad并实现bind并返回,公然无视Monad定律,只要您确定类型正确,Haskell的类型检查器就会很开心。将它称为Monad不会 make 它的行为应该像Monad一样。

戒指也是如此。

特别是,如果您拨打合约方法+ plus- neg* mul0 zero1 one,那么

  • +, 0*, 1应遵守幺半群定律。
  • -应提供+下的反转,即-a + a = 0
  • +应该通勤,即a + b = b + a
  • *应该分配+,即 a * (b + c) = (a * b) + (a * c) (b + c) * a = (b * a) + (c * a)

如果你进一步要求*通勤并且有反转,那么你就有了一个字段。

答案 1 :(得分:3)

我可以更容易地回答这个问题,比较幺半群到半环(即像戒指,但没有否定)。

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

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

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个实例的另一个示例是数字的SumProduct

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中的哪一个更为容易。

请注意,在这两种情况下(bool和数字),有两个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实例是否也遵守分配/零定律(即仿函数法则)。