Brain Rewiring in Progress

Learning Racket is making my head hurt in the best way.

Assumed audience: People who like thinking about learning, and who are up for some programming languages talk. Lots of programming languages talk.

I am slowly, in evenings here and weekends there, working on picking up Racket: a member of the Lisp family. I have bounced off of Lisps repeatedly over the past 15 years of writing software; I managed a tiny bit of Emacs Lisp back when I used Emacs as a daily driver” editor at my first job but that was it.1 I have thought for a few years that I would like to actually learn a language in this family, seeing as it is an integral part of programming language history and that Lisps continue to be incredibly influential in the development of new programming language capabilities. And, frankly: too many people I respect enormously use and love (or have used and loved) Lisps for me to dismiss the value of the linguistic tree.2

However, my best efforts notwithstanding, I have bounced off previous attempts to pick up Clojure or Scheme — including trying, a decade ago, to work through Structure and Interpretation of Computer Programs: trying and failing. I needed a reason to learn the language besides mere interest — something to which I could apply the learnings where I was not already using a different language.3

This time, I am using it as a tool — particularly appropriately, as it turns out — for learning how to build programming languages. This is an itch I have wanted to scratch for many, many years now. (I recall tweeting self-deprecatingly about parsers intimidating me back five years ago, before coming to LinkedIn, for example.) I have done many things in the build-a-language-adjacent space, most of all in my contributions to the design of Glint and Ember.js’ new component authoring format with <template> tags embedded in JavaScript. I have never actually written a parser, though, still less a full compiler.

I picked up two books to that end: Jeremy Sieks Essentials of Compilation: An Incremental Approach in Racket and Shriram Krishnamurthis Programming Languages: Application and Interpretation, and am sloooowly working through them both. Although the Siek volume is available in both Racket and Python versions, I chose Racket, because I think it is far more interesting for me personally… and because I have some Opinions™ about Python at this point and was pretty sure I would be frustrated implementing it that way… and besides, it would not give me the opportunity to rewire my brain the way Racket is.5

Rewiring my brain, I say — indeed, I thus title this post — because the feeling of a language where everything is built on the same constructs all the way down is very odd. To be clear: the feeling is odd. The language itself is not! (I of all people have no right to complain about an overabundance of parentheses.6) I spent some time in DrRacket a few weeks ago just following the chain of definitions of all the different forms back down to their roots in the Racket kernel, and it was honestly somewhat astonishing to see them all boiled down to those handful of special forms” that make up the root of the thing. It is one thing to know in principle that nearly every part of the language is built in terms of those core primitives, including conditionals and so on; it is another entirely to see it in practice.

Similarly, this evening I spent some time thinking about how scoping and evaluation works in Racket (led in part by the tutors” for PLAI), and it was as if I could feel the gears grinding away in my mind, new things slotting into place. (Eager left-to-right, top-to-bottom evaluation + rigorously defined lexical scoping + closures = Ohhhhhh! None of this was wholly novel, but some of the consequences which fall out of that combination initially surprised me — and then slotted into that spot labeled This is obviously correct and everything should work this way” despite the momentary surprise. Indeed: my most-commonly-used language — JavaScript/TypeScript — does work the same way way; but the shift in syntax forced me to deal explicitly with it, where it had previously been implicit.) I associate this feeling of grinding of gears and then things slotting into place with actually learning, and it is a feeling I have been trained since childhood to love. It feels mentally the same way a hard run or a good workout does bodily. It feels good. It makes me excited to keep working through these books — learning Racket, and learning how to build programming languages, and seeing where that takes me.

Here’s to rewiring the brain.


Notes

  1. And no, despite being very Lispy”, I do not count all the Handlebars-based templates I have written over the past 7 years of working with Ember.js. ↩︎

  2. I set aside here the kind of Lisp-hype you might read from Peter Seibel or Paul Graham (though I grant more credence to Seibel than Graham). But this does not mean that (e.g.) Clojure is not a better language than Java; I rather think it almost certainly is. Why and how that might be, and the impact it does or does not have on developers’ productivity or business outcomes, I leave aside entirely here, though I may very well come back to those themes in future posts. ↩︎

  3. Mostly, let us be honest: Rust. ↩︎

  4. or an operating systems class: the other big one I miss on the regular ↩︎

  5. If I were to use that version of the book, I would probably implement with TypeScript or Rust instead. Python is not a terrible language by any stretch, but I have no interest in going back to it. ↩︎

  6. Though, in truth, it is a lot of parentheses, and Rhombus is particularly attractive for example that reason. ↩︎