mal - Make a Lisp
Description
1. Mal is a Clojure inspired Lisp interpreter
2. Mal is a learning tool
Each implementation of mal is separated into 11 incremental, self-contained (and testable) steps that demonstrate core concepts of Lisp. The last step is capable of self-hosting (running the mal implementation of mal). See the make-a-lisp process guide.
The make-a-lisp steps are:
- step0_repl
- step1_read_print
- step2_eval
- step3_env
- step4_if_fn_do
- step5_tco
- step6_file
- step7_quote
- step8_macros
- step9_try
- stepA_mal
Each make-a-lisp step has an associated architectural diagram. That elements that are new for that step are highlighted in red. Here is the final architecture once step A is complete:
If you are interested in creating a mal implementation (or just interested in using mal for something) you are welcome to to join our Discord. In addition to the make-a-lisp process guide there is also a mal/make-a-lisp FAQ where I attempt to answer some common questions.
3. Mal is implemented in 89 languages (95 different implementations and 116 runtime modes)
Presentations
Mal was presented publicly for the first time in a lightning talk at Clojure West 2014 (unfortunately there is no video). See examples/clojurewest2014.mal for the presentation that was given at the conference (yes, the presentation is a mal program).
At Midwest.io 2015, Joel Martin gave a presentation on Mal titled "Achievement Unlocked: A Better Path to Language Learning". Video, Slides.
More recently Joel gave a presentation on "Make Your Own Lisp Interpreter in 10 Incremental Steps" at LambdaConf 2016: Part 1, Part 2, Part 3, Part 4, Slides.
Building/running implementations
The simplest way to run any given implementation is to use docker. Every implementation has a docker image pre-built with language dependencies installed. You can launch the REPL using a convenient target in the top level Makefile (where IMPL is the implementation directory name and stepX is the step to run):
make DOCKERIZE=1 "repl^IMPL^stepX"
# OR stepA is the default step:
make DOCKERIZE=1 "repl^IMPL"
External Implementations
The following implementations are maintained as separate projects:
HolyC
Rust
- by Tim Morgan
- by vi - using Pest grammar, not using typical Mal infrastructure (cargo-ized steps and built-in converted tests).
Q
- by Ali Mohammad Pur - The Q implementation works fine but it requires a proprietary manual download that can't be Dockerized (or integrated into the mal CI pipeline) so for now it remains a separate project.
Other mal Projects
- malc - Mal (Make A Lisp) compiler. Compiles a Mal program to LLVM assembly language, then binary.
- malcc - malcc is an incremental compiler implementation for the Mal language. It uses the Tiny C Compiler as the compiler backend and has full support for the Mal language, including macros, tail-call elimination, and even run-time eval. "I Built a Lisp Compiler" post about the process.
- frock - Clojure-flavoured PHP. Uses mal/php to run programs.
- flk - A LISP that runs wherever Bash is
- glisp - Self-bootstrapping graphic design tool on Lisp. Live Demo
Implementation Details
Ada
The Ada implementation was developed with GNAT 4.9 on debian. It also compiles unchanged on windows if you have windows versions of git, GNAT and (optionally) make. There are no external dependencies (readline not implemented).
cd impls/ada
make
./stepX_YYY