Experiment with the Monkey programming language right here in your browser. MonkeyLab runs on WebAssembly and supports functional patterns like closures and higher-order functions.

MonkeyLab Playground

Try out MonkeyLab directly in your browser with WebAssembly execution.

Language Features

WebAssembly Integration

MonkeyLab compiles to WebAssembly for high-performance execution in the browser.

  • Fast, near-native execution speeds
  • Simple browser integration
  • No external dependencies required

Core Language Features

Based on the Monkey programming language with key extensions:

  • C-like syntax for familiarity
  • Dynamic typing for flexibility
  • First-class functions and closures
  • Arrays and Hash maps

Macro System

Powerful metaprogramming capabilities:

  • Hygienic macros
  • Code generation
  • Compile-time processing

Research Platform

Designed for language theory experimentation:

  • Open source implementation
  • Optimization testing
  • Easy to extend and modify

Documentation

Syntax Guide

MonkeyLab follows a C-like syntax similar to JavaScript.

Variables

Variables are declared using the let keyword:

let x = 5;
let y = "hello";
let z = true;

Control Flow

Standard if/else statements:

if (x > 5) {
    return "greater";
} else {
    return "less or equal";
}

Closure and recursion for iteration:


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

puts("Fibonacci sequence:");
let fibonacci_iter = fn(start, end) {
    let iter = fn(i) {
        if (i < end) {
            puts(fibonacci(i));
            iter(i+1);
        }
    }
    iter(start);
}

fibonacci_iter(1, 10);

Data Types

MonkeyLab has a simple but expressive type system:

Primitive Types

  • Integer: Whole numbers (e.g., 42)
  • Boolean: true or false
  • String: Text enclosed in quotes (e.g., "hello")
  • Null: Represents absence of value

Collection Types

  • Array: Ordered collection (e.g., [1, 2, 3])
  • HashMap: Key-value pairs (e.g., {"key": "value"})

Examples

// Arrays
let numbers = [1, 2, 3, 4, 5];
let first = numbers[0];  // 1


let person = {"name": "Bob", "age": 30};
let name = person["name"];  // "Bob"

Functions

Functions are first-class citizens in MonkeyLab:

// Function declaration
let add = fn(a, b) {
    return a + b;
};


let apply = fn(func, x, y) {
    return func(x, y);
};


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

let counter = makeCounter();
counter();  
counter();  

Macro System

MonkeyLab extends the Monkey language with a powerful macro system:

// Define a simple macro
macro unless(condition, consequence, alternative) {
    quote(
        if (!(unquote(condition))) {
            unquote(consequence);
        } else {
            unquote(alternative);
        }
    );
}


unless(10 > 5, 
    puts("not greater"), 
    puts("greater")
);

Built-in Functions

MonkeyLab provides a set of useful built-in functions:

I/O Functions

  • puts(value) - Prints value to the console with a newline
  • print(value) - Prints value without a newline

Array Functions

  • len(array) - Returns the length of an array
  • first(array) - Returns the first element
  • last(array) - Returns the last element
  • rest(array) - Returns array without the first element
  • push(array, element) - Adds element to the end

Higher-Order Functions

  • map(array, function) - Maps function over array
  • reduce(array, function, initial) - Reduces array
  • filter(array, function) - Filters array by function
let fibonacci = fn(x) {
   if (x < 2) {
        return x;
    } else {
        return fibonacci(x - 1) + fibonacci(x - 2);
    }
};

puts("Fibonacci sequence:");
let fibonacci_iter = fn(start, end) {
    let iter = fn(i) {
        if (i < end) {
            puts(fibonacci(i));
            iter(i+1);
        }
    }
    iter(start);
}

fibonacci_iter(1, 10);
let start = 1;
let end = 100;

let fizzbuzz = fn (i) {
    if (and(rem(i, 5) == 0, rem(i, 3) == 0 )) {
        return "FizzBuzz";
    }
    if (rem(i, 5) == 0) {
        return "Fizz";
    }
    if (rem(i, 3) == 0) {
        return "Buzz";
    }

    return "";
};

let solveFizzBuzz = fn (s, e) {
    if (s > e) {
        return "";
    }

    let v = fizzbuzz(s);

    if (!eq(v, "")) {
        puts(join(s, " = ", v));
    }
    return solveFizzBuzz(s+1, e);
};

puts(start, end);
solveFizzBuzz(start, end);
let map = fn(arr, f) {
    let iter = fn(arr, acc) {
        if (len(arr) == 0) {
            acc
        } else {
            iter(rest(arr), push(acc, f(first(arr))))
        }
    };

    iter(arr, [])
};

let a = [1, 2, 3];
puts(join("original array: ", a), "");
let square = fn (x) {x * x};

puts(join("mapped array: ", map(a, square)));

let reduce = fn(arr, init, f) {
    let iter = fn(arr, acc) {
        if (len(arr) == 0) {
            acc
        } else {
            iter(rest(arr), f(acc, first(arr)))
        }
    };

    iter(arr, init);
};

let reduced = reduce(map(a, square), 0, fn(s, v) {s + v});

puts(join("Reduced Value = ", reduced))



let numbers = [1, 2, 3, 4, 5];

let doubled = map(numbers, fn(x) { return x * 2; });
puts("Doubled: ");
puts(doubled);

let sum = reduce(numbers, 0, fn(acc, x) { return acc + x; });
puts("Sum: ");
puts(sum);

let filter = fn (arr, f_fn) {
    let iter = fn(arr, acc) {
        if (len(arr) == 0) {
            acc
        } else {
            if (f_fn(first(arr)) == true) {
                iter(rest(arr), push(acc, first(arr)))
            } else {
                iter(rest(arr), acc)
            }
        }
    }

    iter(arr, [])
}

let evens = filter(numbers, fn(x) { return rem(x,2) == 0; });
puts("Even numbers: ");
puts(evens);