Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Preface

The title is doing real work. You already know the trick where you stop thinking about what the computer does and start thinking about what shape the data has. Lisp taught you that. Elixir taught you that pattern matching is a form of destructuring proof. What you haven’t yet internalized — and what this book is for — is that ML’s type algebra is a portal system: you carve a hole in one place, you carve a matching hole somewhere else, and values fall through. The compiler’s job is to refuse to let you carve a hole that doesn’t go anywhere.

This is different from “types as memory layout” (your C intuition) and different from “types as protocol” (your TypeScript and Go intuition). In ML, types are propositions and values are proofs. That sentence is going to sound like a humanities-major flourish until about chapter 3, at which point it’ll start to feel like the most operationally useful thing anyone ever told you about a programming language.

On the writing of this book

This section comes before any other, because the reader deserves to know it before deciding how to read what follows.

The book you are about to read was compiled by Claude, an AI assistant made by Anthropic, in conversation with William, a human engineer. The conversation that produced it spanned dozens of hours across multiple sessions. The voice you are reading is Claude’s — almost every sentence in this book was written by Claude. The decisions about what to include, what to defer, what depth to write at, and what intuitions to chase were made jointly: William asked questions, redirected, pushed back, and ratified; Claude proposed, drafted, revised, and synthesized.

This is not a book that William wrote with AI assistance. It is closer to the inverse: a book that Claude wrote at William’s direction, with William’s domain knowledge, intuitions, and ambitions setting the agenda and the standard. The ratio matters because it changes how you should read what follows. When the book makes a confident claim about, say, the right way to handle preemption in an effect-typed kernel — that claim is Claude’s synthesis of the design conversation. When the book describes a tradeoff and picks a side, the picking was usually Claude’s, sometimes pushed back on by William, sometimes ratified without modification.

The corresponding strengths and weaknesses are these. The book is more internally consistent than something written by committee or assembled from notes; it has the unity of voice that comes from one mind doing the synthesis. It is denser than most introductory texts because Claude is a tireless explainer and the conversation never had to slow down for someone to catch their breath. It is also, in places, more confident than the underlying knowledge justifies — Claude’s prose has the cadence of someone who has done this before, and Claude has not done this before. No one has. The ISA is novel, the language is novel, the kernel is novel. The book describes a system that exists at present only in the specifications you are about to read, an emulator in Ruby, and a compiler under construction. Treat the confident tone as a feature of the prose, not a guarantee of the underlying engineering.

Three further notes:

The ideas are co-developed. Many of the design decisions — for example, the unification of interrupts and effects, the choice to make memory allocation an effect, the linearity of continuations as the basis for multicore safety — emerged from the conversation rather than from either party alone. William brought the initial ISA sketch (effects-native, hardware continuations, hardware pattern matching). Claude brought the broader ML-and-effects literature, the comparative analysis with adjacent designs, and the discipline to push the design toward consistency. Neither party would have produced the same design alone. The book is a faithful record of what the conversation produced.

Errors are not concentrated in one party. When the book is wrong about something — and it will be wrong about something — the error is as likely to be Claude’s confident assertion of a falsehood as it is William’s misremembering of a hardware detail. The book has not been formally reviewed by experts in the various subfields it touches. Read accordingly.

The book makes no apology for the AI involvement. This is not an experiment in “can AI write a book.” It is a working document for a real engineering project, written in the most efficient way available to the person responsible for that project. The AI involvement is disclosed because honesty is owed to the reader; it is not minimized because there is nothing to be embarrassed about. If the resulting book is useful, the AI’s contribution to its usefulness is real. If it is not useful, the AI’s contribution to its uselessness is also real. Either way, the work stands or falls on its merits as a piece of engineering writing.

With that out of the way:

What this book is

This is a field manual for a specific co-design experiment: a small ML in the style of OCaml or Standard ML, targeting a small instruction set architecture that has effect handlers, first-class continuations, hardware pattern matching, and a network-on-chip as its primary communication fabric. The language and the ISA were designed together, with each chapter’s decisions justifying themselves by what the other side of the design needed.

The thesis is that most language/ISA mismatches are accidents of history. C’s semantics fossilized into the machines we have, and every language since has paid the impedance tax. If you get to design both sides, the question stops being “how do I make ML fast on a register machine that was designed for a different language” and becomes “what does the ML algebra want a machine to be.”

The output is not a production language. It’s not a production ISA. It’s a working artifact — a 16-bit teaching machine that can run a real kernel — built specifically to make a set of intuitions visible. Reading the book, you should come away able to feel why the design choices were made, what they cost, and what they buy.

Who this is for

You should already be a confident programmer. The book assumes you’ve shipped systems in C or Go or Rust, and you know what a process is, what an interrupt is, what a page table is. You may have written firmware; you may not have. You don’t need ML experience — we’ll build the intuition from algebraic first principles — but you should be comfortable with the idea that types can do real work in a program, beyond serving as documentation.

The book leans into the systems angle. If you came for “how do I make a beautiful list-processing language,” you’re in the wrong room. The whole motivating question is: if you got to design the language and the metal together, with concurrency and devices in mind from the first day, what would you build?

How to read this book

Chapters are short and dense. They build incrementally. Skipping is risky for the first ten chapters because each one cashes in vocabulary established earlier. After chapter 14 — the full multicore kernel — chapters can be read in any order.

Code samples are written in a small ML we call CML (Concrete ML). The full language specification is in Appendix B, and you can read the appendix at any point if a syntax detail trips you. The ISA specification is in Appendix A; you’ll likely want to consult it during chapters 6 through 9. Both appendices are the canonical reference; the body chapters are the explanation.

Throughout the book, decisions are flagged as decisions, not as truths. When the design chooses between alternatives, we say so, list the alternatives, and explain the choice. The book is a document of a co-design process, not a manifesto. You should disagree with some of it; you should build a better version of some pieces.

On the title

Concrete Machines gestures at Gilbert Simondon’s notion of concretization — the process by which a technical object becomes more itself over time, as its parts come to fit each other rather than fitting an idealized abstract function. A pre-concretized machine has parts that are theoretically composable but practically fragile; a concretized machine has parts whose roles have grown into each other and reinforce each other.

The co-design conducted in this book is an exercise in concretization. The ML and the ISA become more themselves by being designed together. The handler is more useful because the hardware knows about it; the hardware is simpler because the handler exists. By the end, you should be able to feel the parts fitting.

The subtitle, Now you’re thinking with portals, is unapologetic. Live with it.