Monkey logo

Monkey

The programming language that lives in books

What is Monkey?

Monkey is a programming language that you can build yourself by reading through Writing An Interpreter In Go and Writing A Compiler In Go.

There is no official implementation of Monkey — it lives in these books and it's up to you, the reader, to implement it. First as a tree-walking interpreter, then as a bytecode compiler and virtual machine.

Here is what Monkey looks like:

// Integers & arithmetic expressions...
let version = 1 + (50 / 2) - (8 * 3);

// ... and strings
let name = "The Monkey programming language";

// ... booleans
let isMonkeyFastNow = true;

// ... arrays & hash maps
let people = [{"name": "Anna", "age": 24}, {"name": "Bob", "age": 99}];

It also has functions!

// User-defined functions...
let getName = fn(person) { person["name"]; };
getName(people[0]); // => "Anna"
getName(people[1]); // => "Bob"

// and built-in functions
puts(len(people))  // prints: 2

And it has conditionals, implicit and explicit returns and recursive functions, which means we can do this in Monkey:

let fibonacci = fn(x) {
  if (x == 0) {
    0
  } else {
    if (x == 1) {
      return 1;
    } else {
      fibonacci(x - 1) + fibonacci(x - 2);
    }
  }
};

But the crown jewel in every Monkey implementation are closures:

// `newAdder` returns a closure that makes use of the free variables `a` and `b`:
let newAdder = fn(a, b) {
    fn(c) { a + b + c };
};
// This constructs a new `adder` function:
let adder = newAdder(1, 2);

adder(8); // => 11

The Monkey Canon

Cover for Writing An Interpreter In Go Writing An Interpreter In Go was published in 2016, its latest version (1.6) was released in 2019.

The first book in the Monkey Canon defines the syntax of Monkey and describes its implementation as a tree-walking interpreter with the following features:

  • Integers, booleans, strings, arrays, hash maps
  • A REPL
  • Arithmetic expressions
  • Let statements
  • First-class and higher-order functions
  • Built-in functions
  • Recursion
  • Closures

Cover for The Lost Chapter The Lost Chapter: A Macro System For Monkey was published in 2017 as a free (to read online or download) addition to Writing An Interpreter In Go.

It can be thought of as Writing An Interpreter In Go's fifth chapter, since builds directly upon the previous four chapters and extends the Monkey interpreter as it stands at the end of the book.

The Lost Chapter: A Macro System For Monkey adds a fully-working Lisp-style macro system to Monkey, that's close to the way Elixir's macro system works.

Cover for Writing A Compiler In Go Writing A Compiler In Go was published in 2018 and its latest version (1.1) in came out in 2019.

This book is the sequel to Writing An Interpreter In Go and while it does not change its syntax and does not add any features, it changes the implementation of Monkey from a tree-walking interpreter into a bytecode compiler and virtual machine.

At the end of the book, Monkey looks and behaves exactly as it did at the end of Writing An Interpreter In Go, except that it's 3x faster!

Monkeys In The Wild

Some readers love to take little detours when following along with the books: a different implementation language, new features, a little twist on the syntax.

And since the code that's presented in the books is MIT licensed, everybody's free to turn their Monkey implementation into whatever their imagination comes up with and showcase it to the rest of the world.

Collected here are some of those interesting and cool Monkey implementations readers have shared with me.

Did you also built your own version of Monkey? Add it to this list by opening a pull request here!


  • An implementation of Monkey in Elixir

  • Rust implementation of Monkey programming language from the book Writing an Interpreter in Go. This interpreter is also compiled into WebAssembly format so it can run on browser.

  • Mico (“Monkey” in catalan). Monkey language implementation done with C++. Including a ton of extensions:

    • Modules
    • Mutability
    • For-loops
    • Intervals

  • A step-by-step walk-through where each commit is a fully working part.
  • prologic's monkey-lang
    Go

    A Monkey implementation in Go that deviates from the book implementations by adding more built-in functions, objects, modules, more operators, assignments -- with the goal of building a self-hosting Monkey implementation.


  • A complete Monkey implementation in Typescript

  • A full Monkey implementation of the bytecode compiler and VM from Writing A Compiler In Go in C#

  • A fully working interpreter for the Monkey programming language as known from the book Writing an Interpreter in Go, written in Dart.

  • Monkey programming language written in Rust. Including compilation to WASM and an online playground

  • This repository started life as the implementation written by gaufung, but it has now diverged significantly in terms of both features and implementation. Including:

    • File I/O
    • A standard library
    • Postfix operators
    • Function argument defaults

  • A Monkey implementation in ISO C11 with additional features:

    • The % modulo operator
    • The logical && and || operators
    • While-loops
    • A built-in type() function to determine the type of a Monkey value

  • This repository contains a C# port of the Monkey programming language from the Writing an interpreter in Go book. Its code closely resembles that presented in the book, but written in idiomatic C# for the .NET Core runtime. Using the instructions below, the interpreter runs on both Windows, Mac, and Linux.

  • The geo programming language based on Monkey.

    Special features:

    • All functions are curried
    • Scopes lives on blocks, no name clashes
    • Pipe operator: the result of one expression becomes the last argument on a subsequent function call expression
    • Unicode support

  • A Monkey implementation in C++ with its own mark-and-sweep garbage collector

  • A Monkey implementation in C++ consistent with the book.
  • Frank Hoogerbeets' SharpBASIC (.zip / .tar.gz)
    Go

    The SharpBASIC interpreter/compiler is based on Thorsten Ball's Monkey language. But SharpBASIC is quite different and should be thought of as sort of a BASIC/Pascal hybrid, but more powerful than BASIC and less verbose than Pascal.

    The language is in its early stages. The interpreter works quite well and there are many working examples in the /ex folder.

    The main characteristic of SharpBASIC is that all definition blocks are marked by the keywords OF..END, while all execution blocks are marked by the keywords DO..END. Look at the CONST, TYPES, IF, SELECT, FOR, WHILE and FUNCTION examples to see how block statements are defined.

    See the info.txt file contained in the archive for information on how to use SharpBASIC.

  • Noprianto's monkey.py
    Python

    A really neat single-file implementation of Monkey in Python with less than 2000 lines of code. It is compatible with Python 2 and Python 3, starting from Python 2.3. The tests are also in one file and can be found here in monkey_tests.py.

  • Java

    This is a simple implementation of the Monkey interpreter in Java. It is compatible with Java 5.0 or later (developed in Java 8, with -source 1.5 -target 1.5, compilation/run test in Java 5.0, 8, and 13). Released as single-file source code, the code is not beautiful, but should work. A compiled Java archive (Monkey.jar) is also available for those who don’t want to compile themselves. Monkey.jar file is also compatible with Java 5.0.

    Need to run Monkey on older systems? Monkey.java can even be compiled in Java 5.0 running on Windows 95 (which was released in 1995). Monkey.jar (released version, compiled in Java 8) can also run on Windows 95. Running latest or released-25-years-ago operating systems? No problem, Monkey is always there.


  • An implementation of Monkey in V
  • Anthony Davis' langur
    Go

    Langur is based on Monkey, but underwent many changes and has features you won't find in Monkey. Some of it's features include:

    • arbitrary precision decimal floating point for numbers
    • integer basex notation for any base from 2 to 36, such as 2x1010_0010 or -11x123A
    • highly expressive switch expressions
    • semi-integrated regex
    • ISO 8601 date/time literals
    • duration literals
    • automated for loop over a list, hash, or string, or over a range
    • first-order functions, including closures
    • immutable or mutable declarations
    • chained string interpolation modifiers
    • both truncating and floor division operators; also remainder and modulus, exponent and root
    • optional database operators (null propagating)
    • catching exceptions without explicit try blocks

    Anthony Davis also wrote a book about how he implemented some of langur's features in a virtual machine that's similar to the one in Writing A Compiler In Go. You can find the book and a free sample at opcodebook.com.


  • Interpreter for the Monkey programming language, in C. With the best name for a Monkey implementation yet.

  • An implementation of Monkey in Nim

  • Ape is an offspring of Monkey, evolved to be more procedural with variables, loops, and more.

    It's implemented in a single C file as a bytecode compiler and VM, including a mark-and-sweep garbage collector.


  • Implementation of Monkey based on the original implementation in Writing An Interpreter In Go and Writing A Compiler In go, except that it has a ton of additional features, such as: logical operators, comments, constants, postfix operators, line numbers in errors, a VS Code syntax highlighting extension (!) and much more.
  • TypeScript

    A TypeScript implementation of Monkey along with an in-browser editor, interpreter, and AST explorer!

  • A Monkey implementation in C++, using the cpp-peglib PEG library for the lexer and parser.

  • Ludwig is a Monkey dialect, an offspring, that has some really interesting differences to Monkey:

    • No statements. Everything is an expression.
    • Structs.
    • Type identifiers, a first step towards enforcing a type system.
    • For/while loops.

  • Monkey implemented in Python, with additional built-in functions, string comparisons, and modulo operator.

  • An implementation of the Monkey interpeter in PHP, with a damn cool logo.

  • A really interesting twist on Monkey, barely recognizable as such: strongly, statically typed; lazy evaluation; pattern-matching, records; and more.

  • Ghost is a small, object-oriented, embeddable scripting language built from the foundations of the Monkey interpreter.
  • Typescript

    A Monkey implementation written in Typescript by David Brownman. It's got extensive tests and is true-to-spec for now.

  • A complete Monkey implementation, including compiler, written in Kotlin

  • A complete Monkey implementation, including compiler, written in Crystal

  • A complete Monkey implementation, including compiler, written in Scala 3

  • A complete Monkey interpreter implementation written in Ruby 3

  • A complete Monkey interpreter implementation written in Python

  • A complete Monkey interpreter implementation written in Lua

  • An implementation of Monkey interpreter in OCaml, including macros.

  • A complete Monkey implementation (interpreter + compiler) in Julia, plus:

    • Macros
    • Mutable variables
    • While loops (with local scopes) and break/continue statements
    • A standalone syntax analyzer extracted from the original compiler
    • A Julia transpiler which tranpiles Monkey to Julia, and behaves almost the same as a real Monkey
    • Unified tests for all three backends (interpreter, compiler and Julia transpiler)

  • Simple implementation of The Monkey Programming Language interpreter in Singkong Programming Language. Singkong is based on Monkey.java, which based on monkey.py. Monkey.singkong is also based on monkey.py.


  • A Monkey implementation written in Swift.

  • A Monkey implementation in F# that is mostly functional.

  • Object-oriented variant inspired by Ruby. It offers “everything is an object”, networking, JSON and more!

  • An implementation of Monkey in Swift

  • An interpreted, dynamically-typed, multi-threaded, general purpose hobby programming language written in Rust. Features:

    • Multiple Data Types: char, int, float, string, array, hash-table, bytes and buffer
    • Arithmetic, Logical operations
    • Variables and Constants
    • Control and Looping structures
    • Functions and Lambda expressions
    • Threads and Multi-threading
    • Shell operator to run shell commands within the language statements
    • Some basic built-in functions
    • Iterators (pseudo iterators)
    • Byte code generation, serialization and loading

  • Pi is an object-oriented, dynamically-typed programming language built from the foundations of the Monkey interpreter.

  • A mostly vanilla implementation of Monkey in Rust with a WASM powered web playground

  • An implementation of Monkey in OCaml, but doesn't require semicolons. That's about it.

  • An implementation of the Monkey Interpreter in Rust. Contains the following features

    • C-like syntax
    • variable bindings
    • Integers and booleans
    • arithmetic expressions
    • built-in functions extended to Arrays and Strings.
    • first-class and higher-order functions
    • closures
    • a string data structure
    • an array data structure
    • a hash data structure

  • An implementation of an interpreter for Monkey in C#

  • An implementation of an interpreter and compiler for Monkey in Scala

  • An implementation of an interpreter for Monkey in Java

  • A Monkey interpreter written in Elm with an online playgound.

  • Monkey interpreter, compiler and formatter, in Rust, with added features.

  • Monkey Lang interpreter implemented in Rust

  • Rust port of the monkey interpreter and the bytecode compiler. It has a few more built-in functions, the unit tests and a way to trace bytecode execution.
  • Go and C

    A functional interpreted programming language with a minimalistic design. Tau differs from Monkey under many aspects but it was made possible thanks to Monkey. Additional features from Monkey:

    • All missing operators
    • Loops
    • Nice error messages
    • Concurrency
    • Pipes (like Go channels)
    • Objects
    • C/Tau interoperability
    • Module/import system

  • Another implementation of Monkey in Elixir

  • A straightforward port of the Monkey Language interpreter in Swift. This has been tested and verified in Swift version 5.9.

  • An implementation of the Monkey Language made in Java. Code features most of the test suite from the book as well.

  • A cheeky simian-inspired interpreter and compiler duo for the Monkey programming language, written in C++. The language features are consistent with those in the original book implementations, and include full test suites and benchmarks.

  • An implementation of the Monkey Language in TypeScript.

  • An implementation of the Monkey Language in Go. Additional Features:

    • Syntax sugar for Uniform Function Call Syntax and Trailing Lambda Syntax
    • VS Code Language Server Extension
    • VS Code Debugger Extension

  • Started as Monkey but now is GROL, on github github.com/grol-io/grol with following notable changes:

    • redesigned the token/lexer/parser with intern'ing
    • no need for custom hash function, go maps of interface can be used for exact equality checks
    • removed let
    • removed requirement for ( ) in if
    • use numerical (uint8) enum (and stringer) instead of strings
    • use said codes for checking type etc everywhere (or even pointer == check thanks for interning)
    • added float, use + for concat of arrays and merging of maps, etc…
    • formatting / normalizing the source code (try it at the web site “run” or cli -format)
    • and more… (see site)

    Also features a WASM online version and a Discord bot.

  • The Cixac programming language is a passion project that I decided to pursue with inspiration and guidance from Thorsten Ball's book. Creating this interpreter is the first (out of three) implementation of my object-oriented dynamic programming language.

  • Rust implementation of the Monkey Programming Language with WASM based Playground.

  • A TypeScript implementation of both a tree walking interpreter and bytecode compiler & vm for Monkey. Extended to support new features including for-in loops, arrow functions, additional builtin functions and more.

  • Pretty much the regular monkey language, with a few customizations:

    • Supports range expressions like 0..123.
    • Supports variable-length arguments to functions with fn(a, ...) { } syntax.
    • Supports builtin functions to turn a vararg object into an array, like fn(a, ...) { a + len(toArray(...)) }.
    • Support a contains builtin that returns a boolean indicating if a Hash object contains a key.
    • Closures capture the environment by value, not by reference, making it truly functional.
    • Implements nicer error reporting, giving contextual information of where the error happened.
    • Apart from the interpreter, it implements the bytecode VM and a transpiler to C++, which turns out to be the fastest.
    • Saves the repl history using liner.

  • A MonkeyLang Interpreter written in C
Copyright © 2024 Thorsten Ball. All rights reserved.