*abusing pattern matching for the greater good*

Roman numerals have the interesting property that they’re easily modeled by a list, and that addition is just mashing all the digits in both numbers together, then ordering all the digits and reducing them by some very simple replacement rules. This makes them a fun way to show off basic pattern matching and a recursive reduction in Haskell.

First the imports and such. Pretty simple.

```
{-# LANGUAGE FlexibleInstances #-}
import Data.List
```

We can define our digits as follows. We’ll add an overlapping instance to show roman numerals, because in our case it makes more sense to order the digits from I to M under the hood, but we’ll need to print them in the correct order from M to I.

```
data RomanDigit = I | V | X | L | C | D | M
deriving (Enum, Eq, Ord, Read, Show)
type RomanNum = [RomanDigit]
instance {-# OVERLAPPING #-} Show RomanNum
where show xs = concatMap show $ reverse xs
```

We can already define addition as described above, but we’ll need to
defer our `condense`

function to the next step. We just mash
the digits together, sort, and condense.

```
romadd :: RomanNum -> RomanNum -> RomanNum
`romadd` b = condense . sort $ a ++ b a
```

The condensing rules are super simple. `condense`

takes a
sorted list of digits from low to high values. If we see IIIII, we
replace with V. If we see VV, we replace with X. And so on. We define a
helper `replaceWith`

function here to keep the list sorted
and move on to the next condensation.

```
= condense . sort $ a : b
replaceWith a b
I:I:I:I:I:xs) = replaceWith V xs
condense (V:V:xs) = replaceWith X xs
condense (X:X:X:X:X:xs) = replaceWith L xs
condense (L:L:xs) = replaceWith C xs
condense (C:C:C:C:C:xs) = replaceWith D xs
condense (D:D:xs) = replaceWith M xs
condense (@(M:_) = num
condense num:xs) = x : condense xs
condense (x= [] condense []
```

Finally, with a bit of elided quasiquotation magic, we have roman numerals that can be simplified as well as added with the most stupid-simple addition algorithm ever created.

```
= do
main print $ condense [roman|MMDCXVVVIIIIII|] -- MMDCXXXI
print $ [roman|VIII|] `romadd` [roman|XVII|] -- XXV
```