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 []) )

リングとモノイドの違いは、リングには「実装するインターフェースに追加のメソッド」があることです。(おそらく私は間違っています)。私にとって、これは結合性に影響を与えるでしょう-しかし、私はこれの完全な意味について頭を悩ませていません.

私の質問は次のとおりです。モノイドとリングの違いの意味は何ですか?

4

2 に答える 2

10

リングを作成するには、追加の方法が必要ですが、十分ではありません。リング構造は、メソッドの動作とそれらの相互作用を管理するルールによって発生します。

たとえば、Monad をインスタンス化し、Monad の法則をまったく無視して bind と return を実装することができます。Haskell の型チェッカーは、適切な型を取得している限り満足します。それをモナドと呼んでも、モナドのように振る舞うわけではありませ

同じことがリングにも当てはまります。

+ plus特に、リングのコントラクト メソッド, - neg, * mul,を呼び出すと0 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)

さらに*通勤して逆にする必要がある場合は、フィールドがあります。

于 2014-03-01T05:34:13.943 に答える
3

モノイドと半環 (つまり、環のようなものですが、否定なし) を比較すると、この質問にもっと簡単に答えることができます。

セミリングを理解する最も簡単な方法はMonoid、特定の方法で互いに相互作用する 2 つの有効なインスタンスが型にある場合に最も一般的に発生するということです。2 つの別個の newtype (インスタンスごとに 1 つ) を定義するよりも、セミリング操作を使用してどのインスタンスを意味Monoidするかを区別する方がはるかに簡単です。Monoid

この例はBoolHaskell の型で、これには 2 つの有効なインスタンスがあり、とnewtypesMonoidを使用して区別します。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/ニュータイプを使用してこれら 2 つのインスタンスをAll区別するのは面倒ですが、セミリングを使用すると、0/をインスタンスの 1 つ (この場合は)に対応させ、/をインスタンス(+)の 1 つに対応させることで、ニュータイプを完全に回避できます。他のインスタンス (この場合):MonoidAny1(*)MonoidAnd

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

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

競合する 2 つのMonoidインスタンスの別の例は、数字Sumの s と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)

通常、(+)/(*)を直接使用して、2 つMonoidの s のどちらを意味するかを明確にする方がはるかに簡単です。

どちらの場合 (bool と数値) もMonoid、問題の 2 つのインスタンスが次のように相互作用することに注意してください。

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そのため、2 つの個別のインスタンスを実装するものに必ずしもセミリングを使用する必要はありません。Monoidまた、これら 2 つのインスタンスが分配/ゼロの法則 (つまり、ファンクターの法則) にも従うことを確認する必要があります。

于 2014-03-01T05:42:51.177 に答える