MEPL is a statically-typed functional programming language with an interactive REPL, implemented in Go.
I already have the mepl binary built, you can run the examples directly.
# Run any example file
./mepl examples/integers.mepl
./mepl examples/functions.mepl
./mepl examples/lists.meplIf you want to build mepl yourself with Docker:
docker build -t mepl .
docker run --rm mepl examples/integers.mepl# Using REPL mode
docker run --rm -it mepl # REPL modeIf you want to build mepl yourself with Go:
Required Go 1.25 or later
go build -o mepl .# Start an interactive REPL
./mepl
# Load a file and then enter the REPL (all declarations available)
./mepl examples/declarations.mepl -igo test ./...MEPL is an expression-based language where everything evaluates to a value. It features static type checking, first-class functions, algebraic data types, and pattern matching.
| Type | Syntax | Description |
|---|---|---|
| Integer | Int |
Whole numbers |
| Boolean | Bool |
true or false |
| String | String |
Text in double quotes |
| Unit | Unit |
The unit value () |
| Function | A -> B |
Function from A to B |
| Pair | (A, B) |
Two-element pair |
| Tuple | (A, B, C, ...) |
N-element tuple (3+) |
| List | [A] |
Homogeneous list |
| Sum | A + B |
Tagged union (left or right) |
| Record | {x: Int, y: Bool} |
Named fields |
| ADT | type Name = Constructor1 | Constructor2 of T |
User-defined algebraic data type with one or more constructors |
// Top-level declaration
let x : Int = 42
// Let-in expression (local binding)
let y = 10 in y + 1
let a = 10 + 3 * 2 // 16
let b = 10 % 3 // 1
let c = -5 // unary minus
let x = true && (false || true)
let y = if x then 1 else 0
let z = 3 == 3 // true
let w = 5 < 10 // true
Functions are defined with fn, applied by juxtaposition (curried by default):
// Single-argument function
let inc : Int -> Int = fn (x: Int) => x + 1
// Multi-argument (curried)
let add : Int -> Int -> Int = fn (x: Int) => fn (y: Int) => x + y
let result = add 3 4 // 7
// Pairs (2 elements)
let p : (Int, Bool) = (1, true)
let a = fst p // 1
let b = snd p // true
// Tuples (3+ elements) with index access
let t : (Int, Bool, String) = (1, true, "hello")
let x = t.0 // 1
let y = t.1 // true
let z = t.2 // "hello"
let xs : [Int] = [1, 2, 3]
let ys = 0 :: xs // [0, 1, 2, 3]
let empty = [] : [Int] // empty list with type annotation
// Case matching on lists
let sum : [Int] -> Int = fix (fn (self: [Int] -> Int) =>
fn (l: [Int]) => case l of
| [] => 0
| h :: t => h + (self t))
let x : Int + Bool = inl 42 as Int + Bool
let y : Int + Bool = inr true as Int + Bool
let describe = fn (v: Int + Bool) => case v of
| inl n => n + 1
| inr b => if b then 1 else 0
let person : {name: String, age: Int} = {name = "Alice", age = 30}
let n = person.name // "Alice"
let a = person.age // 30
ADTs let you define your own named types with multiple constructors. Constructors can be nullary like Red, or carry data like Some of Int. You typically consume ADT values with case pattern matching.
type Color = Red | Green | Blue
type Option = None | Some of Int
let getValue : Option -> Int = fn (opt : Option) =>
case opt of
| None => 0
| Some n => n
let colorName : Color -> String = fn (c : Color) =>
case c of
| Red => "red"
| Green => "green"
| Blue => "blue"
Recursion uses the fixed-point operator fix:
let factorial : Int -> Int = fix (fn (f: Int -> Int) =>
fn (n: Int) => if n == 0 then 1 else n * (f (n - 1)))
for i = 0 to 10 do
println i
end
let s = "Hello" + " " + "World" // concatenation
let len = length s // 11
let ch = charAt s 0 // "H"
print "no newline"
println "with newline"
println 42
println [1, 2, 3]
// Single-line comment
/* Multi-line
comment */
// In mathlib.mepl
let square : Int -> Int = fn (x: Int) => x * x
// In main.mepl
import "mathlib.mepl"
println (square 5) // 25
All examples are in the examples/ directory. For each feature, there is a working example and a type-error example:
| Feature | Working Example | Type Error Example |
|---|---|---|
| Variables | variables.mepl |
variables-errors.mepl |
| Integers | integers.mepl |
integers-errors.mepl |
| Booleans | booleans.mepl |
booleans-errors.mepl |
| Functions | functions.mepl |
functions-errors.mepl |
| Pairs | pairs.mepl |
pairs-errors.mepl |
| Lists | lists.mepl |
lists-errors.mepl |
| Sums | sums.mepl |
sums-errors.mepl |
| Recursion | recursion.mepl |
recursion-errors.mepl |
| Declarations | declarations.mepl |
declarations-errors.mepl |
| Imports | imports.mepl |
imports-errors.mepl |
| Comments | comments.mepl |
comments-errors.mepl |
| Printing | printing.mepl |
printing-errors.mepl |
| Tuples | tuples.mepl |
tuples-errors.mepl |
| Strings | strings.mepl |
strings-errors.mepl |
| Records | records.mepl |
records-errors.mepl |
| Loops | loops.mepl |
loops-errors.mepl |
| ADTs | adt.mepl |
adt-errors.mepl |