Reformat markdown

This commit is contained in:
Nathan McCarty 2025-01-14 15:15:09 -05:00
parent 5a313c952f
commit b0e7c1aa91
14 changed files with 459 additions and 188 deletions

View file

@ -1,6 +1,7 @@
# Year 2015 Day 3
This day provides a gentle introduction to `mutual` blocks and mutually recursive functions.
This day provides a gentle introduction to `mutual` blocks and mutually
recursive functions.
<!-- idris
module Years.Y2015.Day3
@ -23,13 +24,16 @@ import Util
## Parsing and data structures
We'll do parsing a little more properly this time, turning the input into a list of movement commands
We'll do parsing a little more properly this time, turning the input into a list
of movement commands
```idris
data Movement = North | East | South | West
```
We need an effectful operation to parse a single char into a movement. We'll pattern match on the char, and include a catch-all case that throws an error in the event of an invalid char
We need an effectful operation to parse a single char into a movement. We'll
pattern match on the char, and include a catch-all case that throws an error in
the event of an invalid char
```idris
parseMovement : Has (Except String) fs => (x : Char) -> Eff fs Movement
@ -40,7 +44,9 @@ parseMovement '<' = pure West
parseMovement x = throw "Invalid Movement: \{show x}"
```
We also need to be able to translate a `Movement` into a vector of length one pointing in the given direction in coordinate space. Somewhat arbitrarily, we chose 'North' to be positive x and 'East' to be positive y.
We also need to be able to translate a `Movement` into a vector of length one
pointing in the given direction in coordinate space. Somewhat arbitrarily, we
chose 'North' to be positive x and 'East' to be positive y.
```idris
vector : Movement -> (Integer, Integer)
@ -54,11 +60,17 @@ vector West = (0, -1)
### Visited houses
This is a pretty simple task, we are just applying the movements to our current position, and adding our current position to the set of visited locations, so we'll handle this with a normal tail recursive function.
This is a pretty simple task, we are just applying the movements to our current
position, and adding our current position to the set of visited locations, so
we'll handle this with a normal tail recursive function.
To keep the api nice, we wont ask for the set or the starting location in the top-level function, and instead have the top level function initialize the set and location before passing control to the inner tail-recursive variant.
To keep the api nice, we wont ask for the set or the starting location in the
top-level function, and instead have the top level function initialize the set
and location before passing control to the inner tail-recursive variant.
Because the starting location gets a present, we'll add our location to the set before performing the movement, so we will need to add our final location to the set in the recursive base case.
Because the starting location gets a present, we'll add our location to the set
before performing the movement, so we will need to add our final location to the
set in the recursive base case.
```idris
visitedLocations : List Movement -> SortedSet (Integer, Integer)
@ -73,13 +85,26 @@ visitedLocations xs = visitor xs empty (0, 0)
### Robo Santa
This one gets a bit more interesting, we'll adopt the same tail recursive approach, but instead use a `mutual` block and two mutually recursive functions to handle the alternation between santa and robo santa. The `visitSanta` function will pass control to `visitRobo` after executing its movement, and vise versa.
This one gets a bit more interesting, we'll adopt the same tail recursive
approach, but instead use a `mutual` block and two mutually recursive functions
to handle the alternation between santa and robo santa. The `visitSanta`
function will pass control to `visitRobo` after executing its movement, and vise
versa.
We'll want to insert both present deliverer's locations in the recursive base case, this may result in a duplicate location, but that's okay because `SortedSet` will only hold at most one of each item inserted into it.
We'll want to insert both present deliverer's locations in the recursive base
case, this may result in a duplicate location, but that's okay because
`SortedSet` will only hold at most one of each item inserted into it.
In idris, there is a general requirement that values be defined before their use, a common feature of dependently typed languages, resulting from the fact that just having the type signature of a function/value alone is not always enough to perform type checking, as functions can appear as part of types, requiring evaluation of the function and making automatic dependency analysis effectively impossible.
In idris, there is a general requirement that values be defined before their
use, a common feature of dependently typed languages, resulting from the fact
that just having the type signature of a function/value alone is not always
enough to perform type checking, as functions can appear as part of types,
requiring evaluation of the function and making automatic dependency analysis
effectively impossible.
Inside a `mutual` block, elaboration behaves differently, elaborating types first and then values in separate passes. This restricts what you can do a little, but enables mutually recursive functions.
Inside a `mutual` block, elaboration behaves differently, elaborating types
first and then values in separate passes. This restricts what you can do a
little, but enables mutually recursive functions.
```idris
visitedLocations' : List Movement -> SortedSet (Integer, Integer)
@ -103,7 +128,9 @@ visitedLocations' xs = visitSanta xs empty (0, 0) (0, 0)
### Part 1
Similar to the previous day, we get our input, unpack it, and traverse our effectful movement parsing function over it, before feeding that into our solving function.
Similar to the previous day, we get our input, unpack it, and traverse our
effectful movement parsing function over it, before feeding that into our
solving function.
```idris
part1 : Eff (PartEff String) (Nat, List Movement)