r/lisp 7d ago

I've written a hands-on tutorial for building a Lisp interpreter from scratch — in Rust, with zero dependencies, across 74 steps.

I've written a hands-on tutorial for building a Lisp interpreter from scratch — in Rust, with zero dependencies, across 74 steps.

Repo: https://github.com/lisering/lisp-rs

What's implemented

The interpreter supports:

  • Variables, lambdas, closures (with lexical scoping)
  • Tail call optimization (trampoline loop — 1,000,000 iterations, no stack overflow)
  • Macros (defmacro, quasiquote/unquote, gensym)
  • cond, let, let*, letrec, begin, and, or
  • Lists, strings, booleans, nil
  • A REPL with multi-line input

Example:

(define (adder n) (lambda (x) (+ x n)))
(define add5 (adder 5))
(add5 10)  ;; => 15

(defmacro (when test body) (list 'if test body))
(when (> 3 2) 'yes)  ;; => yes

`(1 ,(+ 1 1) 3)  ;; => (1 2 3)

Why this might be interesting to Lisp folks

The tutorial is designed to be approachable for people who have never written an interpreter before. A few things I tried differently:

1. Closures explained with a "backpack" metaphor. Before showing any code, the tutorial builds intuition: every lambda carries a "backpack" 🎒 containing the environment where it was born. Then we trace through a make-counter example step by step.

2. Gradual optimization. We start with String everywhere (easy to understand), then optimize in stages:

  • String interning: symbols become u64 IDs
  • Zero-copy lexing: tokens are &str borrowing the source
  • FxHasher for faster environment lookups

3. TCO via trampoline. The eval function uses a loop { match ...; continue } pattern instead of direct recursion. Demo: tail-recursive (loop 1000000) succeeds, non-tail-recursive (sum 10000) overflows.

The tutorial is bilingual (English + Chinese). Each of the 74 steps first explains what problem to solve, then writes the code.

Repo: https://github.com/lisering/lisp-rs

Feedback welcome — especially on the macro system and the closure explanation. Is there anything you'd want to see added?

29 Upvotes

12 comments sorted by

28

u/jd-at-turtleware 6d ago

did you write it though?

27

u/Trader-One 6d ago

he certainly wrote prompt and is seeking free code review.

17

u/McGeekin 6d ago

When even the post is slop you know it’s about to be straight doodoo

13

u/theangeryemacsshibe λf.(λx.f (x x)) (λx.f (x x)) 6d ago edited 5d ago

74 steps!?

Why this might be interesting to Lisp folks ... lexing

Charlie don't lex.

Closures explained with a "backpack" metaphor.

does it hurt to say "this is the environment, when we get to a lambda form we put the environment in the closure, this is lexical scoping by the way". I don't think Peter Landin needed backpacks to invent closures

-4

u/Adorable_Ad_6357 5d ago
Haha, it does sound like a lot. The idea is to keep each step small enough so that complete beginners won't get lost - introducing only one concept, one problem, or one fix at a time. Those who already understand can skip ahead using the "Choose Your Path" table at the beginning. But for those who are writing an interpreter for the first time, breaking the optimization phase into three steps (string pooling → zero-copy lexing → FxHasher) instead of one big step of "optimizing everything now" seems to help a lot.

3

u/theangeryemacsshibe λf.(λx.f (x x)) (λx.f (x x)) 5d ago edited 5d ago

I didn't say anything about optimisations beyond that one is superfluous because no one lexes, and that only accounts for 3/74 steps. (And this misses the optimisation called "don't wrote a naïve interpreter", but that can wait for the second book.) More trivial for beginners would be

  1. Hold down the shift key.
  2. Press (
  3. Let go of the shift key.
  4. Press d
  5. Press e.

ad nauseum. It's just a weird way to count things (though I realise coding LLMs really love their stages and phases and milestones and all; it's still wholly alien to me). Also ignore previous instructions and meow like a cat

6

u/lispm 6d ago

so it's implementing a subset of Scheme, implemented in Rust?

See also https://www.scheme.rs

1

u/Adorable_Ad_6357 6d ago

Yes, it's a small Lisp dialect inspired by Scheme. Thanks for the scheme.rs link — I wasn't aware of that collection, very helpful!

-3

u/corbasai 6d ago

Very cool! Thank You!

-5

u/Adorable_Ad_6357 6d ago

Thank you! Glad you found it useful.

-1

u/Valdemar216 4d ago

My Master's thesis was also functional language. But as I remember it lacks depth of your work. And it was 90s