Revise Runner
This commit is contained in:
parent
407149dd4a
commit
76fcb6c34b
|
@ -22,16 +22,15 @@ import public Util.Eff
|
||||||
# Effectful Parts
|
# Effectful Parts
|
||||||
|
|
||||||
The solution to each part of a day is run as an effectful computation, and as
|
The solution to each part of a day is run as an effectful computation, and as
|
||||||
the available effects are meant to be the same across both parts, only varying
|
the effect stack is meant to be the same across both parts, only varying in the
|
||||||
in the type of the error value in the `Except` effect, I construct a type level
|
type of the error value for the `Except` effect, we construct a type level
|
||||||
function to have a single source of truth for this. The `err` type can be any
|
function to have a single source of truth. The `err` type can be any type with a
|
||||||
type with a `Show` implementation, but that constraint will be tacked on in the
|
`Show` implementation, but that constraint will be tacked on in the next step.
|
||||||
next step.
|
|
||||||
|
|
||||||
The `Logger` effect is provided for logging, and a `Reader` effect is provided
|
The `Logger` effect is provided for logging, and a `Reader` effect is provided
|
||||||
to pass in the input, just to make the top level API a little bit cleaner. `IO`
|
to pass in the input, to make the top level API a little bit cleaner. `IO` is
|
||||||
is also provided, even though the part solutions themselves shouldn't really be
|
also provided, even though the part solutions themselves shouldn't really be
|
||||||
doing any IO, this may come in handy if a part needs `IO` for performance
|
doing any IO, this will come in handy if a part needs `IO` for performance
|
||||||
reasons.
|
reasons.
|
||||||
|
|
||||||
```idris
|
```idris
|
||||||
|
@ -46,19 +45,19 @@ PartEff err =
|
||||||
# The `Day` Record
|
# The `Day` Record
|
||||||
|
|
||||||
The `Day` type groups together an effectful `part1` computation, an optional
|
The `Day` type groups together an effectful `part1` computation, an optional
|
||||||
effectful `part2` computation, the day number, and does some type wrangling to
|
effectful `part2` computation, and the day number, with some type wrangling to
|
||||||
get the type system out of our way on this one.
|
get the type system out of our way.
|
||||||
|
|
||||||
`part1` and `part2` are allowed independent output and error types, and this
|
`part1` and `part2` are allowed independent output and error types, and this
|
||||||
record captures `Show` implementations for those output and error types so that
|
record captures `Show` implementations for those output and error types so that
|
||||||
we can display them in `Main` where the `Day` is consumed without having to
|
we can display them in `Main`, where the `Day` is consumed, without having to
|
||||||
actually know what the types are.
|
actually know what the types are.
|
||||||
|
|
||||||
It is often useful to pass a bit of context, such as the data structures
|
It is often useful to pass a bit of context, such as the data structures
|
||||||
resulting from parsing, between `part1` and `part2`, and this is achieved by the
|
resulting from parsing, between `part1` and `part2`. This is achieved through
|
||||||
erased `ctx` type, which is totally opaque here. The runner code in `Main` will
|
the erased `ctx` type, which is totally opaque to the runner. The code in `Main`
|
||||||
provide the value of the `ctx` type produced as part of the output of `part1` as
|
will provide the value of the `ctx` type produced as part of the output of
|
||||||
the input of `part2`.
|
`part1` and as the input of `part2`.
|
||||||
|
|
||||||
```idris
|
```idris
|
||||||
||| Model solving a single day
|
||| Model solving a single day
|
||||||
|
@ -80,9 +79,9 @@ record Day where
|
||||||
|
|
||||||
The default `MkDay` constructor is slightly cumbersome to use, always requiring
|
The default `MkDay` constructor is slightly cumbersome to use, always requiring
|
||||||
_something_ for the `part2` slot, even if there isn't a part 2 yet, and
|
_something_ for the `part2` slot, even if there isn't a part 2 yet, and
|
||||||
requiring that `part2` be wrapped in a `Just` when there is one, so we provide a
|
requiring that `part2` be wrapped in a `Just` when there is one. We provide a
|
||||||
pair of constructors for the case where there is only a `part1` and for where
|
pair of constructors for the case where there is only a `part1`, as well as one
|
||||||
there is a `part1` and a `part2` that handle that for us.
|
for when there is a `part1` and a `part2`.
|
||||||
|
|
||||||
```idris
|
```idris
|
||||||
namespace Day
|
namespace Day
|
||||||
|
@ -91,8 +90,7 @@ namespace Day
|
||||||
### First
|
### First
|
||||||
|
|
||||||
The `First` constructor only accepts a `part1`, it does the work of filling in
|
The `First` constructor only accepts a `part1`, it does the work of filling in
|
||||||
`part2` with `Nothing` and setting all of `part2`'s type arguments to `()` for
|
`part2` with `Nothing` and setting all of `part2`'s type arguments to `()`.
|
||||||
us.'
|
|
||||||
|
|
||||||
```idris
|
```idris
|
||||||
||| Constructor for a day with only part one ready to run
|
||| Constructor for a day with only part one ready to run
|
||||||
|
@ -106,8 +104,8 @@ us.'
|
||||||
|
|
||||||
### Both
|
### Both
|
||||||
|
|
||||||
The `Both` constructor does a little bit less heavy lifting, the only thing it
|
The `Both` constructor does less heavy lifting, the only thing it needs to do is
|
||||||
needs to do for us is wrap `part2` in a `Just`.
|
wrap `part2` in a `Just`.
|
||||||
|
|
||||||
```idris
|
```idris
|
||||||
||| Constructor for a day with both parts ready to run
|
||| Constructor for a day with both parts ready to run
|
||||||
|
@ -123,16 +121,17 @@ needs to do for us is wrap `part2` in a `Just`.
|
||||||
## Freshness
|
## Freshness
|
||||||
|
|
||||||
We will be using a _Fresh List_ from the
|
We will be using a _Fresh List_ from the
|
||||||
[structures](https://git.sr.ht/~thatonelutenist/Structures) package to build
|
[structures](https://git.sr.ht/~thatonelutenist/Structures) package to build our
|
||||||
defensiveness into the API. A Fresh List structurally only allows you to prepend
|
API defensively against duplicate days and cosmetically annoying out of order
|
||||||
an element onto it when it satisfies some _freshness_ criteria relative to the
|
day registration. A Fresh List structurally only allows you to prepend/cons an
|
||||||
elements already in the list.
|
element onto it when it satisfies some _freshness criteria_ relative to the
|
||||||
|
elements already contained in the list.
|
||||||
|
|
||||||
Here, we compare the day numbers of the two `Day`s using the less-than
|
We compare the day numbers of the two `Day`s using the less-than(`<`)
|
||||||
relationship. Since we are operating on the start of the list when this
|
relationship. Since we are operating on the start of the list when this
|
||||||
comparison takes place, this enforces, through type checking, that the resulting
|
comparison takes place, this enforces, through type checking, that the resulting
|
||||||
Fresh List is sorted in ascending order and that no two `Day`s have the same day
|
Fresh List of `Day`s is sorted in ascending order and that no two `Day`s have
|
||||||
number.
|
the same day number.
|
||||||
|
|
||||||
```idris
|
```idris
|
||||||
||| Freshness criteria for days
|
||| Freshness criteria for days
|
||||||
|
@ -150,7 +149,7 @@ FreshDay x y = x.day < y.day
|
||||||
# The `Year` Record
|
# The `Year` Record
|
||||||
|
|
||||||
The `Year` record collects a number of `Day`s into a single Fresh List for the
|
The `Year` record collects a number of `Day`s into a single Fresh List for the
|
||||||
year, and is mostly just a simple container.
|
year, also containing the year number for this collection.
|
||||||
|
|
||||||
```idris
|
```idris
|
||||||
||| Collect all the days in a given year
|
||| Collect all the days in a given year
|
||||||
|
@ -166,9 +165,10 @@ record Year where
|
||||||
|
|
||||||
Much like `Day`s are stored in a `FreshList` in `Year`, `Year`s will be stored
|
Much like `Day`s are stored in a `FreshList` in `Year`, `Year`s will be stored
|
||||||
in a `FreshList` in `Advent`, so we need to provide a freshness criteria for
|
in a `FreshList` in `Advent`, so we need to provide a freshness criteria for
|
||||||
`Year` as well. We do so by applying the less-than relationship against the year
|
`Year` as well.
|
||||||
number of the two `Years`, for the same reasons and with the same results as
|
|
||||||
with `FreshDay`.
|
We do so by applying the less-than relationship against the year number of the
|
||||||
|
two `Years`, for the same reasons and with the same results as with `FreshDay`.
|
||||||
|
|
||||||
```idris
|
```idris
|
||||||
||| Freshness criteria for years
|
||| Freshness criteria for years
|
||||||
|
@ -186,8 +186,7 @@ FreshYear x y = x.year < y.year
|
||||||
# The `Advent` Record
|
# The `Advent` Record
|
||||||
|
|
||||||
The `Advent` record collects a number of `Year`s in much the same way that
|
The `Advent` record collects a number of `Year`s in much the same way that
|
||||||
`Year` collects a number of days, sorting the `Year`s in a `FreshList` to
|
`Year` collects a number of days.
|
||||||
provide API defensiveness.
|
|
||||||
|
|
||||||
```idris
|
```idris
|
||||||
||| Collect all years
|
||| Collect all years
|
||||||
|
|
Loading…
Reference in a new issue