[英]What are the implications of the differences between a monoid and a ring?
這是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中基於此的一個環的示例:
(defprotocol ring
(plus [x y])
(mult [x y])
(neg [x])
(zero [])
(one []) )
它似乎是 - (借用Java的說法), 環和幺半群之間的區別在於環具有“實現接口的附加方法”。 (也許我錯了)。 現在對我來說,這會對相關性產生影響 - 但我並沒有全神貫注於這一點。
我的問題是: 幺半群和戒指之間的差異有什么影響?
其他方法是必要的但不足以制作戒指。 環結構由管理方法行為及其相互作用的規則產生。
例如,您可以實例Monad並實現bind並返回,公然無視Monad定律,只要您獲得正確的類型,Haskell的類型檢查器就會很高興。 稱這是一個單子並不能使它像一個單子應該不過。
戒指也是如此。
特別是,如果你調用一個環的合約方法+ 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)
如果你還要求*
通勤並且有反向,那么你就有了一個字段。
我可以更容易地回答這個問題,比較幺半群與半環(即環狀,但沒有否定)。
理解半環的最簡單方法是,當類型具有兩個以特定方式相互交互的有效Monoid
實例時,它們最常出現。 而不是定義兩個獨立的newtypes(每個Monoid
實例),它更容易使用的半環操作來區分哪些Monoid
情況下,我們的意思。
一個例子是Haskell中的Bool
類型,它有兩個有效的Monoid
實例,我們使用Any
和All
newtypes進行區分:
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
newtypes消除這兩個實例的歧義是一種痛苦,但是如果我們使用半環,那么我們可以通過使用0
/ (+)
來對應Monoid
實例中的一個來完全避免newtypes(在這種情況下) Any
)和1
/ (*)
對應另一個Monoid
實例(在本例中為And
):
instance Num Bool where
fromIntegral 0 = False
fromIntegral 1 = True
(+) = (||)
(*) = (&&)
兩個競爭的Monoid
實例的另一個例子是Sum
和Product
的數字:
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
的兩個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
實例是否也遵守分配/零定律(即函子定律)。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.