--- title: "Multiple Typeclass Instances using Newtype in Haskell" date: 2022-04-28T23:09:42-07:00 expirydate: 2022-04-28T23:09:42-07:00 tags: ["Haskell"] draft: true --- > And I have known the eyes already, known them all— > > The eyes that fix you in a formulated phrase . . . It sometimes feels like the data types that we work with are simply too locked down through their typeclass instances. A type might have multiple law-abiding implementations of the required methods, and yet only one implementation can be used in an `instance` declaration. First, let's take a look at some type classes and types for which this is true, starting with `Monoid`. ### The `Monoid` Type Class Recall that for a type `m` with `Monoid m`, the following things are available: * An associative binary operation, `(<>)`. Associativity means that for any three elements of `m`, like `a`, `b`, and `c`, the following holds: ```Haskell (a <> b) <> c == a <> (b <> c) ``` * An neutral element under `(<>)`, called `mempty`. It being the neutral element means that using it with `(<>)` doesn't do anything. For any `a :: m`, we can (with minor notation abuse) write the following: ```Haskell a <> mempty == mempty <> a == a ``` This is a pretty broad specification, actually. Many types have multiple different operations that satisfy the `Monoid` laws. Let's take a look at a few of them, starting with integers. #### Integers Addition is an associative binary operation. Furthermore, it's well-known that adding zero to a number leaves that number intact: \\(0+n = n + 0 = n\\). So we might define a `Monoid` instance for numbers as follows. Note that we actually provide `(<>)` via the `Semigroup` class, which _just_ requires the associative binary operation, and serves as a superclass for `Monoid`. ```Haskell instance Semigroup Int where (<>) = (+) instance Monoid Int where mempty = 0 ``` Cool and good. But hey, there are other binary operations on integers! What about multiplication? It is also associative, and again it is well-known that multiplying anything by one leaves that number as it was: \\(1\*n = n\*1 = n\\). The corresponding `Monoid` instance would be something like the following: ```Haskell instance Semigroup Int where (<>) = (*) instance Monoid Int where mempty = 1 ``` But we can't have both. Haskell yells at us: ``` Duplicate instance declarations: instance Semigroup Int -- Defined at test.hs:1:10 instance Semigroup Int -- Defined at test.hs:7:10 Duplicate instance declarations: instance Monoid Int -- Defined at test.hs:4:10 instance Monoid Int -- Defined at test.hs:10:10 ``` Okay, so we can have at most one. But that's not good. Fortunately, thanks to the `Num` instance for `Int`, we get functions that are pretty much the same as `fold`, except specialized to multiplication and addition: ```Haskell fold :: (Foldable t, Monoid m) => t m -> m product :: (Foldable t, Num a) => t a -> a sum :: (Foldable t, Num a) => t a -> a ``` This takes care of _most_ of the uses we have for `(+)` and `(*)`; it does, however, prevent us from using `Int` with [`MonadWriter`](https://hackage.haskell.org/package/mtl-2.2.2/docs/Control-Monad-Writer-Lazy.html#t:MonadWriter). #### Booleans