如何在这个 Or 类型上定义一个 mempty ?

How to define a `mempty` on this `Or` type?

在 Haskell Programming from first Principles 一书中,有一个练习要求我在 Or 类型上实例化 Monoid

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 是一个 Monoid,显然它应该是 mempty,其中 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 = (<>)

简而言之:您对(<>)的定义不能用作幺半群的二元运算符。除非可以保证 a(或者 b 如果我们使用 Snd 作为 "neutral element" 的构造函数)只有一个可能的值。

according to the above rules, apparently a Fst x should be the mempty if it was a Monoid.

确切地说,如果它是 monoid [wiki]。但是对于一个幺半群,可以证明存在*恰好一个个恒等元。证明如下:给定有两个中性元素e1e1,则表示e1⊕e2=e1 ,但同时e1⊕e2=e2(因为 a⊕e=e⊕a=ae 一致元素),所以这意味着 e1=e2 成立,因此两者是一样。

现在在您的 (<>) 定义中没有这样的标识元素。的确,说这个元素是Fst e,那么它应该是:

Fst e <> Fst a = Fst a

它成立(你定义的第一行),但它也应该成立:

Fst a <> Fst e = Fst a

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

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

因此我们可以得出结论,您的 (<>) 函数 适合作为幺半群的二元运算符。您将需要想出一个不同的二元运算符,其结构可以在幺半群中使用。

现在身份元素仍然可能是 Snd e 形式,但话又说回来:

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

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

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

后者不成立(因为 x 可能不同于 e)。