0

In the book Haskell Programming from first Principles, there is an exercise which asks me to instantiate Monoid on an Or type:

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

previously, we defined the rules when instantiate 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

according to the above rules, apparently a Fst x should be the mempty if it was a Monoid, where x is anything of type a. But I don't know how to write the rules:

instance (Monoid a, Monoid b) => Monoid (Or a b) where
  mempty = ???  -- Please help me with this, to make every (Fst x) be mempty.
  mappend = (<>)
cmal
  • 2,062
  • 1
  • 18
  • 35
  • A monoid has always *exactly one* "neutral element". So it is likely that you here mean `Fst mempty`? But then this is still not a monoid, since `Fst x <> Fst mempty` will return `Fst mempty`, even if if `x /= mempty`. So I have the impression that your `(<>)` is not fit for a monoid. – Willem Van Onsem Oct 23 '18 at 11:29

1 Answers1

6

In short: your definition for (<>) can not be used as the binary operator for a monoid. Unless one can guarantee that there is only one possible value for a (or b if we use Snd as the constructor for a "neutral element").

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

Exactly, if it was a monoid [wiki]. But for a monoid it can be proven that there exists *exactly one identity element. The proof is as follows: given there are two neutral elements e1 and e1, then it means that e1⊕e2=e1, but at the same time e1⊕e2=e2 (since a⊕e=e⊕a=a holds with e an identity element), so that means that e1=e2 holds, and thus the two are the same.

Now in your definition of (<>) there is no such identity element. Indeed, say that this element is Fst e, then it should hold that:

Fst e <> Fst a = Fst a

which holds (the first line of your definition), but it should also hold that:

Fst a <> Fst e = Fst a

and this will, according to your (<>) function only hold if a is e. The only way we can thus declare this a monoid is if we can only define one value in the Fst constructor, like @leftroundabout says, for example:

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

We can thus conclude that your (<>) function is not suited as a binary operator for a monoid. You will need to come up with a different binary operator that is structured in such a way that this can be used in a monoid.

Now it could still be possible that the identity element is of the form Snd e, but then again:

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

should both hold, whereas in your implementation:

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

the latter will not hold (since x can be different from e).

Willem Van Onsem
  • 443,496
  • 30
  • 428
  • 555
  • Actually one _could_ write monoid instances based on the OP's `<>` – but they would have to be isomorphic to `instance Monoid (Or () b)`. – leftaroundabout Oct 23 '18 at 12:08
  • @leftaroundabout: ah, indeed. Updated. – Willem Van Onsem Oct 23 '18 at 12:12
  • Awesome explanation. Just for clear, this is why the book ignores the Or type when asking the reader to define Monoid. That was all because of my mistake to mention there is such an exercise. But I learned a lot from this. Thanks! – cmal Oct 23 '18 at 13:14