MLisp - First steps

2026.01.27

Writing a Lisp interpreter is a bit of a ritual passing for a programmer.

After giving it a go and giving up a couple of times, I really made an effor this time and have gotten to great start.

The current version of MLisp is about 427 lines of code. Really not that much, but there are (famous) examples of even smaller Lisp interpreters such as Tinylisp - Lisp in 99 lines of C.

I'm not aiming for a small or even lightweight Lisp interpreter. My focus (at this time) is in learning how to create an interpreter and learning Rust.

The functionality of MLisp shown below is really a testament to the elegance of the Lisp language design. In only 427 lines of code mlisp can do:

(+ 1 2 3)
(- 9 4)
(* 2 (/ 9 3))
(define x 10)
(+ x 3)
(define square (lambda (x) (* x x)))
(square x)
(quote (1 2 3))
(let ((a 1) (b 2)) (+ a b x))
(first (quote (1 2 3)))
(rest (quote (1 2 3)))

The examples above are a first indication of the MLisp language. I'm not creating MLisp to be a Scheme or Common Lisp implementation. Instead I want to explore some ideas behind the Lisp family of languages and develop something of my own.

One thing that immediately jumps out in the example above is the use of define which reminds us of Scheme. Instead of car or cdr I picked first and rest. I'm not entirely sold on the define keyword and will probably replace it with def as I like that better.

MLisp currently only comes as a REPL and file loading is not implememented yet.

Interpreter file size

An interesting aside on the interpreter file size.

After hacking together the first version of MLisp I had a binary size of about 400 KB. This version did not have readline support, meaning that key bindings such as C-a or C-p (along with REPL history) did not work. I found a Rust readline implementation called rustyline that worked great. But adding this package (and it's required dependencies) increased my binary size to 1.1M!

This is something I really don't like: the advantage of package managers such as cargo, pip or npm is tremendous, finding and using packages is really easy. But just pulling in dependencies like this also screws you over sizewise. The rustyline package I use for readline support has 18 (!!) dependencies.

The current REPL works good for small examples but one thing it can't do is multiline editing. I'll probably end up not supporting that as file loading (and supporting Slime/Swank!) would be sufficient.

Back to MLisp Blog