A toy Haskell compiler written in Zig
Built collaboratively with AI assistance. Exploring compiler construction, one curried function at a time.
Rusholme is an area in Manchester, England, famous as "the Curry Mile" — a vibrant street lined with Indian restaurants. Since currying is the signature technique from Haskell (after the mathematician Haskell Curry), the name was irresistible.
This project serves two purposes simultaneously:
By building a real, non-trivial compiler from scratch
Implementing a full Haskell frontend and multiple backends
Zig + LLVM optimization for blazing-fast compilation
LLVM native, WebAssembly, JIT/lli, C, and JavaScript targets
Call-by-need semantics preserved through GRIN
Collaborative human-AI development approach
A modern, pragmatic pipeline inspired by GHC but simplified for educational purposes
Hand-written recursive descent parser with full Unicode support. Produces a complete Haskell 2010 AST.
GHC's System F_C with type annotations. The type-safety firewall — if Core typechecks, later stages are trusted.
Replaces STG+Cmm. Explicit memory operations (store/fetch/update) while preserving lazy evaluation semantics.
Written in Zig. Handles heap allocation, thunk evaluation, I/O, and provides cross-platform runtime support.
Infrastructure
Hello World
Basic Programs
Optimisations
Polish
Closed 1 hour ago
GRIN (Graph Reduction Intermediate Notation) is Rusholme's central IR, sitting between Core and the machine backends. Unlike GHC's STG, GRIN makes every heap operation explicit — there is no implicit allocation hiding behind calling conventions.
| Stage | Rusholme | GHC | Role |
|---|---|---|---|
| High-level IR | Core (System FC) | GHC Core (System FC) | Type-checked, explicit types |
| Explicit-heap IR | GRIN | STG | Allocation, thunks, evaluation |
| Low-level IR | LLVM IR | Cmm / LLVM IR | Machine-level operations |
swap
Consider this simple Haskell function that swaps the fields of a pair:
module Nodes where
data Pair = Pair Int Int
swap :: Pair -> Pair
swap (Pair a b) = Pair b a
swap = \r [ds]
case ds of {
Pair a b ->
Pair [b a];
};
\r is a calling convention marker ("re-entrant"), not explicit code. Pair [b a] allocates on the heap — but this is implicit, inferred by the STG-to-Cmm lowering from info tables and closure entry points.
swap arg_0_1 =
case arg_0_1 of
(CPair a_2 b_3) ->
store (CPair b_3 a_2) ;
\node_5 ->
pure node_5
_ ->
pure #"Non-exhaustive patterns"
store is the only way to allocate on the heap — it is a first-class monadic operation. The result is bound to node_5 via a monadic continuation \node_5 ->, making the heap address explicit and inspectable at every optimisation pass.
Every heap write is a store instruction.
Every heap read is a fetch.
Every thunk update is an update.
No hidden operations behind info tables or closure entry points.
GRIN is a monadic IR: store returns a heap
pointer that is bound to a fresh variable via \x ->.
This gives every allocated node a named identity, perfect for
whole-program heap analyses.
Because allocation is explicit and first-class, heap analyses (points-to, sharing, liveness) can operate directly on the IR without needing a separate abstract interpretation of calling conventions or info tables.
Further Reading
GRIN was introduced by Boquist & Johnsson (1996) in "The GRIN Project: A Highly Optimising Back End for Lazy Functional Languages". The key insight is that making heap operations first-class enables a family of whole-program transformations — including sharing analysis, dead heap elimination, and update avoidance — that are difficult to express on STG.
Full architectural documentation, design decisions, and rationale
Rusholme targets WebAssembly via its WASM backend, enabling browser-based Haskell evaluation without installing the compiler.
The REPL below compiles Haskell expressions to WebAssembly binaries (.wasm) right in your browser.
Type expressions and press Enter to evaluate — multi-line blocks supported with :{ ... :}.
Press Enter to evaluate • Ctrl+C to clear • {:{ and :} for multi-line blocks
Rusholme is an open, collaborative project. Whether you're interested in compilers, Zig, Haskell, or just want to learn alongside us — there's a place for you.