Preparing for Advent of Code 2025 with Unison
#unison #adventofcode #aoc2025
Advent of Code is back again and I'm joining in the fun! This year, I'll try solving it with Unison, a statically typed functional language with some very neat ideas about content-addressable source code and distributed computing. It has a proprietary cloud backend, but you can also run it on your own machines, and it recently had its 1.0 release.
What follows are my very first ignorant baby steps coding in Unison.
Pure Functional Programming
I have some experience with other pure functional programming languages. There will, of course, be some differences, but I'm going to assume that I can pick it up as I work through the puzzles. That's what AoC is all about!
If you're not familiar with this style of programming, I recommend Elm or Clojure as starting places. They're quite different (Elm is a little closer to Unison), but both very illuminating, and more approachable if you're coming from something like Python or JavaScript.
The Unison Codebase Manager
When I've worked on Advent of Code in the past I've used languages like Chapel, Rust, or Gleam where you write code in files, you edit code in files, and you run code from files.
Unison... doesn't work like that.
You do write your code in text files, but rather than living there you load it into your content-addressed, append-only codebase with a tool called the Unison Codebase Manager (or ucm).
It feels a bit like using a REPL: you write your code, ucm watches for changes and does type checking, runs tests, etc. When you're satisfied with the code you're working on you run an update command at the ucm prompt and your functions are imported.
I followed the tour of the Unison workflow to get a feel for how it works. I wouldn't say it's comfortable yet, but I'm ready to get started which is all we need!
Reading Puzzle Input
Rather than using the Advent of Code API I like to get my puzzle inputs manually, read them from a file, and then paste the output to check. I'm a bear of little brain, and sometimes I need to get hands on with debugging my code!
To approach AoC this way I need to know how to:
- Read input from a file
- Parse that input into a data structure
- Print output to the terminal
This is slightly complicated by the way Unison handles “effects”, which includes things like input and output. Full treatment is beyond the scope of this writeup, but the relevant functions are documented in base.IO.
Printing a file is easy enough: we can use printLine anywhere in our main function. Reading a file involves constructing the path, opening the file, and reading it as text.
Putting these parts together looks something like:
main : '{IO, Exception} ()
main =
use IO *
do
inputPath = FilePath "input/foo.txt"
inputHandle = open inputPath Read
input = getAllText inputHandle
printLine input
Parsing is trickier.
There are tools in the base language for doing parsing, but they're quite simplistic. In particular, they don't handle parsing recursive structures, which is something that past AoC puzzles have required. On the other hand, sometimes puzzles start with tidy nested structures but then switch to considering the input in a more ad-hoc fashion.
For now, I'll try using the built-in parsing tools, but I'll figure out how to bring in a more sophisticated parsing library if I need it.
Sharing Solutions
Another lovely feature of AoC is reading solutions from other developers. Seriously: BurntSushi's 2018 solutions in Rust taught me more about working in that language than hours of noodling on code did.
Unison programmers seem to share code on Unison Share instead of GitHub. There's even an Advent of Code template pinned to the front page!
I followed the instructions in Unison share code hosting to get a feel for this. I'm not sure if my code will be valuable to anyone, but I'll publish it here anyways!