First Principles & Scheme

(Or, The Value of Working at Lower Levels of Abstraction.)

I’m loving working in Scheme because it forces me to work from First Principles.

There’s a huge value in the convenience functions that most languages wrap around those first principles, but it’s like buying and using a car vs. building the car you’re using.

The latter is more work but you’re going to really understand how that car works and you’re going to have the perfect car for your needs.

Some languages (cars) are built for speed (Rust, Go). Some are built for user happiness (Ruby). Some are built for making a specific task easy (SQL). Each has its pros and cons.

Scheme feels like it’s built to be buildable. It’s the Lego™ set of languages.

Like Lego™ if you want to quickly build some complex thing, it’s going to require a lot more time and effort unless you’ve got some pieces pre-built (by you or others). Like Lego™ there is very little limitation to what you can do with it.

The car you build won’t necessarily be the fastest possible car, but it will be the perfect car for your needs. Imagine making a pick-up truck that lets you safely chain additional truck-beds to it when you have big loads. No-one makes a car/truck like that. They make faster cars. They make better looking cars. They make cars your kids can drive. But they don’t make the perfect car for every use case.

Understanding first principles allows you to create that perfect vehicle for your needs. Most languages are pre-built cars. Some are highly specialized Formula-1 models that will send inexperienced developers hurtling into the wall at high speed. Some are comfortable Honda station wagons that’ll get you to your destination safely. Some are Porche 911’s: fun, relatively safe, go reasonably fast, but they’re terrible for taking the whole family and picking up groceries.

Most of the time, that’s perfect. You get the right kind of car for the type of stuff you’re doing. If you’re writing cutting edge video games it’s probably the Formula-1. It’ll be hard to steer, and easy to crash, but you can go really fast with it. If you’re writing a typical webapp it’ll be the Honda station wagon: safe, easy to drive, san handle a load of unexpected groceries, plenty of service stations.

From a productivity perspective it’s great to be able to hop into a “normal” car and just drive. You don’t have to worry about weather much because it’s got windshield wipers, heater, and AC built in. You just want to get to your destination relatively quickly and comfortably.

But, it’s terrible for ever learning how the car works, or how to make something more appropriate than the car they handed you.

And that brings us back to Lego™ and Scheme. Frankly, they’re both terrible for getting things done quickly if all you have is the raw pile of “Bricks”. But they’re spectacular for learning how to make things, and thus how to make a thing perfectly suited to your current needs.

Once you learn those first principles, AND you’ve chosen a scheme with good libraries,1 you’re left with a tool for building the perfect thing for your needs.

Scheme is a machine shop with a lathe and a cutter. Scheme + libraries is a machine shop with a lathe, a cutter, a CNC, and all the other machines people built with their machine shops.

Ruby + libraries (for example) is a woodshop with saw, chisel, hammer, and a bunch of useful Jigs built by other woodworkers.

Practical Realities

But.. that’s just a tool shop. I want a tool box 99% of the time

Python is a toolbox. It’s not the fastest & not the best. But it builds pretty quickly 🤷‍♀️

Not saying I wouldn’t learn Scheme. Just prioritizing trade offs. e.g., I learned C++ in 2018 for reasons. - Joshua Kehn

Josh’s got a good point. That type of thinking is embraced by basically every programmer trying to get something built in a timely manner. For example when my coworkers and I sit down to work we either use Ruby + Rails or Elixir + Phoenix. We’re not just working in high level languages, we’re also using libraries that give us _skyscraper levels of abstraction_. It’s all about using off-the shelf tools that’ll get us to our destination quickly. For us, making reliably things quickly translates either directly, or indirectly into money.

But, some folks who really understood first principles had to spend a lot of time building those abstractions. I’m incredibly grateful to them, but I don’t want to be limited to their abstractions, and I don’t want to be tied to their choice of language to use them.

For example. Let’s take the Maybe Monad. It’s incredibly useful, but Ruby didn’t have that baked in. So some rails developer who understood first principles added the .try method. It took until ~2016 for Ruby to add .dig.

.try and .dig are incredibly useful, but if you didn’t understand the core principles of programming you either wouldn’t think to add them, or you’d implement it in a worse way, because you aren’t aware that there are established and efficient patterns for implementing that stuff.

This brings me back to why I love Scheme. There are geeks who love reading academic and abstract programming guides that have no direct practical bearing on their day job, and critically can actually remember the stuff the next week. Then, there are the rest of us, who don’t remember any of that crap unless we actually use it, repeatedly.

Scheme forces me to use it. Scheme forces me to understand it. Every day I spend programming Scheme I better understand fundamental concepts that give me more options in my day job. Every day I use Scheme I build up a few more abstractions in code that are perfectly suited to my tasks and my way of approaching those tasks.

To put it another way, by having so little baked in, and having such great support for building good things, I’m building my own perfect framework.

Would it have been faster to use Ruby + Sinatra? Absolutely. Would the end result have met my goals as well? Not even remotely. Would I have learned anything along the way? Not a chance.

So, yes, I’m going to reach for Ruby or Elixir in my day job. But for my personal work, I’m going to keep working in Scheme and improving my libraries, and eventually I’ll have my own framework, that is more efficient than Rails or Phoenix for the things I’m trying to accomplish.


  1. Racket and Chicken Scheme both have great collections of pre-built libraries. Racket’s language, and library ecosystem have some of the best documentation available for any language.