Early Access · v0.5.0

ML types.
Effects as capabilities.
Actors, compiled native.

March is a statically typed functional language for programs built from actors. It takes message passing and supervision from the BEAM and algebraic data types from ML, and compiles the result to a native binary through LLVM. Memory is managed by Perceus reference counting with in-place reuse, so there is no garbage collector and no pauses, and functional code runs at Rust-like speed.

Safety is the compiler's job, not the test suite's.

Side effects are part of the type: a module declares the capabilities it needs, so what any piece of code can touch is visible in its signature, bounded by what main was granted, and auditable across every dependency you pull in. Linear types make a resource that is used out of order, twice, or never a compile error. Refinement types reject a value a function cannot accept before it runs. A message protocol is checked on both sides, a crashed actor is restarted the way you declared, and a running node takes new code without a restart.

Capabilities

The whole program is bounded by main

main's capability parameter is the program's grant. Everything it reaches has to fit under it: every helper, every stdlib call, every dependency. Reach past it and the build fails, naming the chain that got there.

Three layers, one function

What, in what order, with what values

Capabilities say what resources code may touch. Linear types and typestate say how many times, and in what order, a resource is used. Refinement types say with what values a function may be called. They are independent, they compose on the same function, and all three fire at compile time.

Protocols

Typed conversations, two parties or twenty

Write the conversation once. Each role gets a typed module, so a send out of turn, a second receive, or a role that stops halfway does not compile; a runner connects the roles over the network, each its own program on its own machine.

Hot deploy

New code into a running node, gated by what it may do

forge deploy hot ships only the functions that changed; actors keep their state and migrate it in place. A patch that reaches for authority the running version did not have stops until you grant it by name, and the node's own policy can still refuse it.

Concurrency

Actor model, typed and isolated

Share-nothing message-passing actors with supervision trees. Accidental shared mutable state is a compile error, not a runtime bug.

Performance

Zero-allocation recursive transforms

FBIP rewrites uniquely-owned data in place, so transforms like this allocate nothing on the reuse path. The functional-style rewrite is automatic; no unsafe code required.

See benchmarks →

Benchmark

tree-transform(depth=20, 100 passes)

After pass 1, March allocates nothing — every node rewritten in-place. 7.5× faster than OCaml. 19× faster than Rust. Apple M-series, --opt 2.

LanguageMedianAllocs/pass
Elixir (BEAM)2580 ms2M
OCaml (ocamlopt)3825 ms2M
Rust (rustc -O)9977 ms2M
March (FBIP)513 ms0 ✓

← Back

See how March feels to write.

Full playground — no install needed ↗
march — interactive
March REPL — type an expression and press Enter.
march>

Get started in minutes

One command installs on macOS and Linux.

1 — Install
2 — Open the interpreter