132 lines
3.9 KiB
Markdown
132 lines
3.9 KiB
Markdown
# [Year 2015 Day 12](https://adventofcode.com/2015/day/12)
|
|
|
|
This day provides an introduction to our new
|
|
[`Parser.JSON`](../../Parser/JSON.md) module, as well as the use of `DList`s[^1]
|
|
to collect values from an indexed type family into a single collection.
|
|
|
|
```idris hide
|
|
module Years.Y2015.Day12
|
|
|
|
import Control.Eff
|
|
|
|
import Runner
|
|
```
|
|
|
|
```idris
|
|
import Structures.Dependent.DList
|
|
|
|
import Parser
|
|
import Parser.JSON
|
|
```
|
|
|
|
## Parsing
|
|
|
|
Parse a list of JSON values into a `DList`.
|
|
|
|
`JSONValue`'s type constructor has the signature `JSONType -> Type`, forming
|
|
what is known as an "Indexed Type Family".
|
|
|
|
Each type of JSON value has a separate type, e.g. a Bool has type
|
|
`JSONValue TBool`, a String has type `JSONValue TString`, etc. While these are
|
|
all separate types, they all share the `JSONValue` component of the type
|
|
constructor, making them members of the same family.
|
|
|
|
Despite being members of the same type family, they still have different types,
|
|
so we can't just shove `JSONValue`s of different types into, say, a
|
|
`List JSONValue`, we need a collection with some amount of heterogeneity. While
|
|
a `List (type : JSONType ** JSONValue type)` would _work_, that introduces
|
|
various ergonomic headaches, so instead we return a `DList`[^1], a `List` like
|
|
data structure specifically designed for collecting values from an indexed typed
|
|
family into a single collection.
|
|
|
|
The parsing logic is otherwise quite simple, we use the `many` combinator to
|
|
turn the `value` parser, which parses a single JSON value, into one that parses
|
|
a list of JSON values, and then use `DList`'s `fromList` method to collect the
|
|
results into a `DList`.
|
|
|
|
```idris
|
|
parseJsons : Has (Except String) fs => Has IO fs => (input : String)
|
|
-> Eff fs (types : List JSONType ** DList JSONType JSONValue types)
|
|
parseJsons input = do
|
|
result <- runFirstIO (many value) input
|
|
case result of
|
|
Left err => throw $ show err
|
|
Right result => pure $ fromList result
|
|
```
|
|
|
|
## Solving
|
|
|
|
A reducer for `DList.dFoldL` that sums all the numbers within the contained JSON
|
|
Value.
|
|
|
|
The outer function is meant to be called on a top level object, using
|
|
`DList.dFoldL` on a `DList` of `JSONValue`s, where as the inner function
|
|
directly reduces a `JSONValue` using `JSON.dFoldL`.
|
|
|
|
```idris
|
|
sumNumbers : Double -> (type : JSONType) -> (value : JSONValue type) -> Double
|
|
sumNumbers dbl type value = dFoldL sumNumbers' dbl value
|
|
where
|
|
sumNumbers' : Double -> (type : JSONType) -> (value : JSONValue type) -> Double
|
|
sumNumbers' dbl TNumber (VNumber d) = dbl + d
|
|
sumNumbers' dbl _ value = dbl
|
|
```
|
|
|
|
Filter out objects containing a "red" key
|
|
|
|
```idris
|
|
noRed : (type : JSONType) -> (value : JSONValue type) -> Bool
|
|
noRed TObject value =
|
|
let (types ** vals) = getValues value
|
|
in case dFind (\t, v =>
|
|
case t of
|
|
TString => v == (VString "red")
|
|
_ => False
|
|
) vals of
|
|
Nothing => True
|
|
Just _ => False
|
|
noRed _ value = True
|
|
|
|
sumNumbersNoRed :
|
|
Double -> (type : JSONType) -> (value : JSONValue type) -> Double
|
|
sumNumbersNoRed dbl type value =
|
|
case dFilter noRed value of
|
|
Nothing => dbl
|
|
Just value => sumNumbers dbl type value
|
|
```
|
|
|
|
## Part Functions
|
|
|
|
### Part 1
|
|
|
|
Parse our JSONs, then fold our `sumNumbers` reducer over them.
|
|
|
|
```idris
|
|
part1 : Eff (PartEff String)
|
|
(Double, (types : List JSONType ** DList JSONType JSONValue types))
|
|
part1 = do
|
|
input <- askAt "input"
|
|
(types ** values) <- parseJsons input
|
|
let result = dFoldL sumNumbers 0.0 values
|
|
pure (result, (types ** values))
|
|
```
|
|
|
|
### Part 2
|
|
|
|
```idris
|
|
part2 : (types : List JSONType ** DList JSONType JSONValue types)
|
|
-> Eff (PartEff String) Double
|
|
part2 (types ** values) = do
|
|
let result = dFoldL sumNumbersNoRed 0.0 values
|
|
pure result
|
|
```
|
|
|
|
```idris hide
|
|
public export
|
|
day12 : Day
|
|
day12 = Both 12 part1 part2
|
|
```
|
|
|
|
## References
|
|
|
|
[^1]: <https://git.sr.ht/~thatonelutenist/Structures/tree/trunk/item/src/Structures/Dependent/DList.md>
|