Charlie KrugThe Build Log

← All posts

A REPL hands you the answer. This one hands you the rewrite.

Chalkstep runs a hand-written Scheme interpreter one reduction at a time. Paste your own recursion and watch it rewrite itself down to a value, the way SICP chalks it on the board.

Watch someone teach recursion and they don't run the code, they rewrite it. (factorial 3) becomes (if (= 3 0) 1 (* 3 (factorial (- 3 1)))), which becomes (* 3 (factorial 2)), which keeps going, each new line written under the last, until a bare number falls out the bottom. That chalkboard derivation is the substitution model, the mental tool SICP hands you for reading recursive procedures. And it's the one thing every online Scheme REPL throws away. You type an expression, you get an answer, and the rewrite that connects the two happens invisibly inside a call stack you never see.

Chalkstep is that call stack, drawn. Paste a small program, definitions and one calling expression, hit Step, and the call redraws itself in place, one reduction per click, with the sub-expression that just changed circled in chalk yellow. A REPL gives you the answer. This gives you the rewrite.

The whole thing is one function

A normal interpreter is a function evaluate(expr, env) that returns a value. It recurses into itself, the intermediate forms live and die on the machine's stack, and you only ever see what comes back at the end. Chalkstep is built around a different primitive. Its core is step(expr, env) that returns not a value but the next expression: the same program with exactly one substitution-model reduction applied. Substitute the arguments into a procedure body, that's a step. Collapse (= 3 0) to #f, that's a step. Reduce an if whose test is now known, that's a step.

The nice part is that step isn't a second implementation bolted onto the evaluator. Call it in a loop until the expression stops changing and you have the evaluator, since running every reduction to the end is exactly what evaluation is. Call it once and render the result and you have the visualizer. The interpreter and the teaching tool are the same engine looked at from two zoom levels, which means there's no risk of the animation quietly disagreeing with how the language actually computes. The picture can't lie, because the picture is the computation.

One reduction, not one eval

The granularity is a deliberate choice, and it's what makes the rewrite legible rather than a blur. A single procedure call might take a dozen steps to fully unwind: substitute the arguments, reduce the test, pick the if branch, reduce the recursive call, and so on. A coarser tool would run the whole call and show you the before and after. Chalkstep stops after each individual reduction, the same way a lecturer writes one line at a time instead of erasing the board and writing the final answer.

Steps operate on the parsed tree, not the source text, and each new tree is printed back to Scheme (printer.ts) before it hits the screen. That's why the board always shows valid, readable code and never a half-rewritten string with a dangling paren. The reader underneath is hand-written, a lexer and parser with no parsing-library dependency, because a black-box eval would hide the exact reductions the tool exists to expose.

What it deliberately can't do

This is a teaching visualizer, not a production Scheme. The language subset is small and chosen: define, lambda, if and cond, quoting, arithmetic and comparison primitives, pairs, and recursion, plus enough to show the SICP closure pattern ((define add5 (make-adder 5)) then (add5 10) reduces step by step, closure and all). No call/cc, no macros, no tail-call trickery. Breadth would only dilute the one thing it does well. Even the failures are part of the lesson: an unbalanced paren, an unbound variable, or applying a non-procedure render as an inline chalkboard message, not a console crash, so a student pasting broken code still learns something from the break. The interpreter core carries 195 tests at over 99% line coverage, which is the kind of number you want behind a tool whose whole claim is that its steps are correct.

Try it

Open Chalkstep. The factorial demo is pre-filled: click Load, then press the right arrow (or the space bar) and watch (factorial 5) rewrite itself all the way down to 120, each reduction circled as it happens. Rewind, scrub to any point in the derivation, then clear the board and paste your own recursive definition to see it unfold. The full source is on GitHub.

Chalkstep is live. Free, in your browser, no signup.

This post is part of the build log: every app my automated factory ships gets written up here, honestly. Browse everything at apps.charliekrug.com. Comments are open below.

Comments

Loading comments…