Advent of Code 2024 - Day 4
The last few days of Advent of Code have been fairly
straightforward and I have
not really used any new language features of Gleam. I do
feel like I am better at spotting where the list.fold
function is useful, but
on day 4 there was a great opportunity to make use of the use
funcitonality.
Before jumping in with my explanation, Isaac Harris-Holt
made a video about use
in Gleam which is very good, so I encourage you to
watch that first before I describe how I used in on day 4.
So the use
essentially takes a function, whose final argument is a callback
function, and allows you to define the callback function immediately after the
use
line. For example the following code which doubles each number in a list
using a callback function
fn example_callback() {
list.map([1, 2, 3], fn(x) {
2*x
})
}
can be rewritten without the additional indentation as below.
fn example_use() {
use x <- list.map([1, 2, 3])
2*x
}
These are functionally equivalent returning [2, 4, 6]
.
In today’s problem we had to parse a 140
by 140 grid of letters into a structure we could arbitrarily search to find a
combination of letters in horizontal, vertical, and diagonal directions. I
decided to use a dict.Dict
with the position of the character in X-Y coordinates
as the key, and the letter as the value. This ended up being very easy to do
with use
and list.index_fold
. The parsing function I wrote takes a list
of lines and is shown below. I called the dictionary “map” in this example,
which is probably not the best name.
fn parse(lines: List(String)) -> Dict(Point, String) {
use map, line, y <- list.index_fold(lines, dict.new())
let characters = string.to_graphemes(line)
use map, c, x <- list.index_fold(characters, map)
let p = #(x, y)
dict.insert(map, p, c)
}
This is equivalent to writing the function below.
fn parse(lines: List(String)) -> Dict(Point, String) {
list.index_fold(lines, dict.new(), fn(map, line, y) {
let characters = string.to_graphemes(line)
list.index_fold(characters, map, fn(map, c, x) {
let p = #(x, y)
dict.insert(map, p, c)
})
})
}
I like the way use
simplifies the look of the function once you get used to it,
however it is important to note that for each use
you end up going one nested
callback deeper. It can take a little time to get used to this syntax. My full
solutions for all the problems are available on github.