My ZuriHac 2023 talk

I gave a talk at Zurihac 2023. Macgyver’s Haskell Compiler: Combinators, Duct Tape, and Two Minutes:

These take a while to load, because each page loads my compiler and then compiles code embedded in the page. See the git repo mentioned during the talk for build instructions.

Eagle-eyed viewers may have noticed localhost:3000 in my browser. This is because I served these files using my hoc tool.

I used the Firenvim browser extension to open Neovim within a slide and then access a terminal to build my compiler.

Many thanks to the organizers of the event. A special thanks to Farhad Mehta for inviting me and for suggesting the title of my talk.

I should have said…​

The slide showing the Church/Scott-encoding of Booleans should have used f g instead of x y, as the variables correspond to different cases and not fields.

I forgot to demo a few things, which is just as well as I was running out of energy towards the end. Perhaps I can show them off in a future talk. Or you can just try them out here.

The following "ChatFP" tool is a slightly prettier version of the Haskell compiler embedded on one of my slides.

Paste the example featured on

primes = filterPrime [2..] where
  filterPrime (p:xs) =
    p : filterPrime [x | x <- xs, x `mod` p /= 0]

Click the play button at the bottom. Since this is a definition, the input is printed, and a new textarea element appears. In general, this widget accepts any number of definitions at once, that is, a Haskell program.

Now try take 100 primes. This time, an expression is detected. Like GHCi, those of type IO _ are run; otherwise, if the type has a Show instance, the value is printed.

Along with this interpreter, I also wanted to show the combinators produced by my compiler and demonstrate lazy evaluation via the following lines:

espy True  -- Explore Scott encodings.
espy $ Just 'x'
espy foldr
abc = ['a'..'z']
espy abc  -- Shows a big mess; you can see the dictionary selector.
take 12 abc
espy abc  -- Less messy, can see 12 constants.
espy abc  -- Normal form.

Another example:

fac n = if 1 < n then n * fac (n - 1) else 1 :: Int
espy fac  -- The `*` means itself. Unevaluated dictionary selectors.
fac 1
espy fac  -- Much better!

Without the Int annotation, the fac function is polymorphic and hence more verbose because it can always handle any Ring instance.

There is also a rudimentary module system, but I’d rather not explain it until I’ve improved it.

Ben Lynn 💡