Day 13 was the first real foray into Haskell's typeclass system, with the implementation of an `Ord`

instance for a custom data type. Some functions in `Data.List`

made the rest of the processing easy.

## Data type

The problem wanted me to define an ordering for packets, so I had to be able to represent packets. This required a new data type, and a parser for it.

```
data Packet = List [Packet] | Element Int
deriving (Eq)
pairsP = pairP `sepBy` (endOfLine <* endOfLine)
pairP = (,) <$> (packetP <* endOfLine) <*> packetP
packetP = listP <|> elementP
elementP = Element <$> decimal
listP = List <$> ("[" *> (packetP `sepBy` ",")) <* "]"
```

Next was to define how packets should be ordered. This was the definition of the `Ord`

typeclass for this type. I chose to define `compare`

, following the rules given in the problem description. The definition of this function allows Haskell to provide all the other comparison operators for this data type.

```
instance Ord Packet where
(Element a) `compare` (Element b) = a `compare` b
(Element a) `compare` (List bs) = (List [Element a]) `compare` (List bs)
(List as) `compare` (Element b) = (List as) `compare` (List [Element b])
(List []) `compare` (List []) = EQ
(List []) `compare` (List (_:_)) = LT
(List (_:_)) `compare` (List []) = GT
(List (a:as)) `compare` (List (b:bs))
| a `compare` b == EQ = (List as) `compare` (List bs)
| otherwise = a `compare` b
```

## Solving the problems

For part 1, I used `uncurry (<)`

to convert each pair into the Boolean showing if it was correctly ordered, then find the indices of the `True`

values (adding 1 to each to make it one-based numbering.

`part1 = sum . fmap (1 +) . elemIndices True . fmap (uncurry (<))`

Because `Packet`

is an instance of `Ord`

, the standard `sort`

function works on lists of `Packet`

s. That meant part 2 was just finding which elements of the sorted packet list were dividers, then multiplying them.

```
part2 pairs = product dividerLocations
where dividers = [ List [List [Element 2]] , List [List [Element 6]] ]
packets = dividers ++ concatMap (\(a, b) -> [a, b]) pairs
dividerLocations = fmap (1 +) $ findIndices (`elem` dividers) $ sort packets
```

## Code

You can get the code from my locally-hosted Git repo, or from Gitlab.