Mere: Building a Language
A design diary of Mere, a small ML-family language with a region/view memory model, capability-passing effects, self-hosting in the browser, code generation to four backends (interpreter / C / LLVM / Wasm), and type-safe concurrency. Less about the finished product, more about the decisions: what was built, how, which problems came up, and how they were solved.
What this series is
Mere is a small ML-family programming language — Hindley–Milner type inference, algebraic data types, pattern matching — built up until it could type-check, evaluate, and compile itself in a browser, generate code for four backends (a tree-walking interpreter, C, LLVM IR, and WebAssembly), and run type-safe concurrency across all of them.
This series is not a tour of the finished language. It is a record of the decisions: what each piece is, how it was built, which problems showed up, and how they were resolved. Where a choice was a genuine fork, the alternatives and the reason for picking one are part of the story — including the times the answer was “don’t build this yet.”
The idea behind Mere
One belief shapes almost every decision:
Optimize for the verifiability of correctness, and make the implicit explicit.
Concretely:
- The implicit is removed on purpose. Anything whose runtime representation or behavior silently changes is pushed into the open — memory ownership, effects, and (later) which values may cross a thread boundary all become things you can see in the types.
- Compromise is unavoidable, so choose where. Every design page names the trade-off it is making rather than pretending there isn’t one.
- Verbosity is acceptable. The code is written with AI assistance, so “more to type” is not the cost it once was. That frees the design to be explicit where a human-first language would hide things for brevity.
None of this is about being clever or fast. It is about being able to look at a program and know what it does.
How the pieces were decided
A pattern runs through the whole project and recurs in almost every episode:
- A paper trial — think a design through on paper (and often a throwaway prototype) before committing.
- Open questions, structured — undecided points are filed as
Q-###and left open on purpose; they get answered as implementation forces the issue. - Dogfooding — real programs are run through the toolchain to surface the problems a design document can’t.
The arc
- Foundations — the philosophy, choosing OCaml as the host, and a minimal ML core that runs.
- Memory — five strategies distilled into a unified region/view model,
with
Trivial,Drop, andwith. - Effects — side effects passed as capabilities, with fine-grained borrow annotations, rather than hidden ambient state.
- Code generation — one language, four backends, kept in lock-step.
- Self-hosting — Mere’s own lexer, parser, formatter, evaluator, type checker, and code generator, written in Mere, running in the browser.
- Concurrency —
spawn/ channels /par_mapwithSend/Synctype safety, across every backend. - What’s next — and, just as importantly, what was deliberately not built.
Start anywhere, but the parts build on each other roughly in this order.