如何在此“或”类型上定义“空”?

时间:2018-10-23 11:26:36

标签: haskell monoids

在《第一原理的Haskell编程》一书中,有一个练习要求我在Monoid类型上实例化Or

data Or a b =
  Fst a
  | Snd b
  deriving (Eq, Show)

以前,我们在实例化Semigroup时定义了规则:

instance Semigroup (Or a b) where
  (Fst _) <> (Fst y) = Fst y
  (Fst _) <> (Snd y) = Snd y
  (Snd x) <> (Fst _) = Snd x
  (Snd x) <> (Snd _)= Snd x

根据上述规则,显然Fst x应该是mempty,如果它是Monoid,其中xa类型的任何东西。但是我不知道如何写规则:

instance (Monoid a, Monoid b) => Monoid (Or a b) where
  mempty = ???  -- Please help me with this, to make every (Fst x) be mempty.
  mappend = (<>)

1 个答案:

答案 0 :(得分:6)

简而言之:您对(<>)的定义不能用作monoid的二进制运算符。除非可以保证a仅存在一个可能的值(如果我们使用b作为“中性元素”的构造函数,则为Snd)。

  

根据上述规则,如果Fst xmempty,显然应该是Monoid

的确,如果 monoid [wiki]。但是对于一个半身像,可以证明确实存在一个一个身份元素。证明如下:给定有两个中性元素 e 1 e 1 ,则表示 e 1 ⊕e 2 = e 1 ,但同时 e 1 ⊕e 2 = e 2 (因为a⊕e=e⊕a= a 保持一致> e 一个标识元素),因此表示 e 1 = e 2 成立,因此两者相同

现在您对(<>)的定义中没有这样的标识元素。的确,假设此元素为Fst e,则应认为:

Fst e <> Fst a = Fst a

包含(定义的第一行),但也应包含:

Fst a <> Fst e = Fst a

,这将根据您的(<>)函数仅在ae时成立。因此,我们可以这样声明一个Monoid的唯一方法是,如果我们只能在Fst构造函数中定义 one 值,例如@leftroundabout这样说:

instance Monoid (Or () b) where
    mempty = Fst ()
    mappend = (<>)

因此,我们可以得出结论,您的(<>)函数不适合作为Monoid的二进制运算符。您将需要提供一个不同的二进制运算符,该二进制运算符的结构方式使其可以在monoid中使用。

现在,identity元素仍然有可能是Snd e的形式,但是再次出现:

(Snd x) <> (Snd e) = Snd x
(Snd e) <> (Snd x) = Snd x

应该都成立,而在您的实现中:

(Snd x) <> (Snd _)= Snd x

后者将不成立(因为x可以与e不同)。