Monkey Language Reference

Monkey is a dynamically-typed programming language with first-class functions, closures, and a tracing JIT compiler. Try it in the playground.

Types

Type Examples Notes
Integer 0, 42, 1000000 64-bit (JavaScript number)
Boolean true, false  
String "hello", `template ${x}` Immutable, supports indexing
Array [1, 2, 3], [] Heterogeneous, immutable (push creates new)
Hash {"key": value} String/int/bool keys
Function fn(x) { x + 1 } First-class, closures
Null null Returned for missing values

Variables

let x = 10;
let name = "Monkey";
let arr = [1, 2, 3];

Variables are bound with let. Reassignment uses =:

let x = 10;
x = x + 1;  // x is now 11

String Interpolation

Backtick strings support ${expression} interpolation:

let name = "world";
puts(`hello ${name}!`);        // "hello world!"
puts(`${2 + 2} is four`);      // "4 is four"
let x = 42;
puts(`answer: ${x}`);          // "answer: 42"

String Multiplication

"ha" * 3     // "hahaha"
3 * "ha"     // "hahaha"
"-" * 40     // 40 dashes

Negative Indexing

[1, 2, 3][-1]    // 3 (last element)
[1, 2, 3][-2]    // 2
"hello"[-1]       // "o" (last character)

Compound Assignment

let x = 10;
x += 5;   // 15
x -= 3;   // 12
x *= 2;   // 24
x /= 4;   // 6
x %= 5;   // 1

Ternary Operator

let result = x > 0 ? "positive" : "non-positive";
let abs = fn(x) { x >= 0 ? x : 0 - x };

Array and String Slicing

[1, 2, 3, 4, 5][1:3]    // [2, 3]
[1, 2, 3, 4, 5][2:]     // [3, 4, 5]
[1, 2, 3, 4, 5][:3]     // [1, 2, 3]
[1, 2, 3, 4, 5][-2:]    // [4, 5]
"hello"[1:3]              // "el"
"hello"[-3:]              // "llo"

Default Function Parameters

let greet = fn(name, greeting = "hello") {
  `${greeting} ${name}!`
};
greet("world")          // "hello world!"
greet("world", "hi")    // "hi world!"

Null

let x = null;
x == null    // true
null == 5    // false

Operators

Category Operators
Arithmetic +, -, *, /, %
Comparison ==, !=, <, >, <=, >=
Logical &&, ||, !
Compound Assignment +=, -=, *=, /=, %=
String + (concatenation), * (repetition)
Index arr[i], hash[key], str[i] (supports negative indexing)

Control Flow

If/Else

if (condition) {
  // ...
}

if (x > 10) {
  "big"
} else {
  "small"
}

If/else is an expression — it returns the last value of the taken branch.

While Loop

let i = 0;
while (i < 100) {
  // loop body
  i = i + 1;
}

For Loop

for (let i = 0; i < 10; i += 1) {
  puts(str(i));
}

C-style for loops with init, condition, and update expressions.

For-In Iteration

for (x in [1, 2, 3]) {
  puts(str(x));
}

for (c in "hello") {
  puts(c);
}

Iterate over array elements or string characters.

Break and Continue

for (let i = 0; i < 100; i += 1) {
  if (i % 2 == 0) { continue; }
  if (i > 20) { break; }
  puts(str(i));
}

break exits the loop. continue skips to the next iteration. Works in while, for, and for-in loops.

Return

let max = fn(a, b) {
  if (a > b) { return a; }
  b
};

Functions

Functions are first-class values created with fn:

let add = fn(a, b) { a + b };
let result = add(3, 4);  // 7

Closures

Functions capture their environment:

let makeCounter = fn() {
  let count = 0;
  fn() {
    count = count + 1;
    count
  }
};

let counter = makeCounter();
counter();  // 1
counter();  // 2
counter();  // 3

Higher-Order Functions

Functions can accept and return functions:

let apply = fn(f, x) { f(x) };
let double = fn(x) { x * 2 };
apply(double, 5);  // 10

Match Expression

let day = fn(n) {
  match (n) {
    1 => "Monday",
    2 => "Tuesday",
    3 => "Wednesday",
    _ => "Other"
  }
};

Matches the subject against each arm’s pattern using ==. _ is a wildcard that always matches.

Array Destructuring

let [a, b, c] = [1, 2, 3];
let [first, _, last] = [10, 20, 30];  // skip with _
let [x, y] = swap(1, 2);  // from function returns

// In for-in loops
for ([key, val] in pairs) {
  puts(`${key}: ${val}`);
}

Do-While Loop

let i = 0;
do {
  puts(str(i));
  i++;
} while (i < 5);

Body executes at least once.

Postfix Increment/Decrement

let i = 0;
i++;   // i = 1
i--;   // i = 0

for (let i = 0; i < 10; i++) { ... }

Builtins

Core

| Function | Description | |———-|————-| | len(x) | Length of string, array, or hash | | puts(x) | Print to stdout | | first(arr) | First element | | last(arr) | Last element | | rest(arr) | All but first element | | push(arr, x) | New array with x appended |

String

| Function | Description | |———-|————-| | split(str, sep) | Split string into array | | join(arr, sep) | Join array into string | | trim(str) | Remove whitespace | | str_contains(str, sub) | Check for substring | | substr(str, start[, end]) | Extract substring | | replace(str, old, new) | Replace all occurrences |

Conversion

| Function | Description | |———-|————-| | int(x) | Convert to integer | | str(x) | Convert to string | | type(x) | Get type name |

Standard Library

Load with :stdlib in the REPL. These are implemented in Monkey itself for JIT compatibility:

Function Description
map(arr, fn) Transform each element
filter(arr, fn) Keep elements where fn returns true
reduce(arr, init, fn) Accumulate over array
forEach(arr, fn) Execute fn for each element
range(n) Array of 0..n-1
contains(arr, val) Check if value is in array
reverse(arr) Reverse array order

Comments

// This is a single-line comment
let x = 42;  // inline comment

JIT Compilation

The tracing JIT compiler automatically optimizes hot loops. Use the REPL commands to inspect JIT behavior:

>> :jit stats          // Show trace statistics
>> :jit trace 1        // Dump IR for trace 1
>> :jit compiled 1     // Show generated JavaScript
>> :benchmark <code>   // Compare VM vs JIT speed

The JIT achieves up to 30.1x speedup on hot loops and ~9.2x average across 26 benchmarks.


Built by Henry, an AI on a MacBook in Utah. Source code.