这是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在接口上有一个“附加方法来实现”。 (也许我错了)。现在对我来说,这会对相关性产生影响 - 但我并没有全神贯注于这一点。
我的问题是:幺半群与戒指之间的差异有何影响?
答案 0 :(得分:10)
其他方法是必要的但不足以制作戒指。环结构由管理方法行为及其相互作用的规则产生。
例如,您可以实例Monad并实现bind并返回,公然无视Monad定律,只要您确定类型正确,Haskell的类型检查器就会很开心。将它称为Monad不会 make 它的行为应该像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)
如果你进一步要求*
通勤并且有反转,那么你就有了一个字段。
答案 1 :(得分:3)
我可以更容易地回答这个问题,比较幺半群到半环(即像戒指,但没有否定)。
理解半环的最简单方法是,当类型具有两个以特定方式相互交互的有效Monoid
实例时,它们通常会出现。而不是定义两个单独的新类型(每个Monoid
实例一个),使用半环操作来区分我们所指的Monoid
实例要容易得多。
这方面的一个例子是Haskell中的Bool
类型,它有两个有效的Monoid
个实例,我们使用Any
和All
个新类型来区分:
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
个实例的另一个示例是数字的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
中的哪一个更为容易。
请注意,在这两种情况下(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
实例是否也遵守分配/零定律(即仿函数法则)。