https://github.com/no-way-labs/mo
Mo is a strict functional language whose OCaml compiler generates efficient imperative Zig — no ownership annotations, no garbage collector. Linearity inference, stateful pattern fusion, and opaque linear handles let pure functional code match or beat hand-written Zig on memory across 5 benchmarks.
https://github.com/no-way-labs/mo
compiler compiler-optimization functional-programming language-design linear-types ocaml programming-language stream-fusion systems-programming zig
Last synced: about 8 hours ago
JSON representation
Mo is a strict functional language whose OCaml compiler generates efficient imperative Zig — no ownership annotations, no garbage collector. Linearity inference, stateful pattern fusion, and opaque linear handles let pure functional code match or beat hand-written Zig on memory across 5 benchmarks.
- Host: GitHub
- URL: https://github.com/no-way-labs/mo
- Owner: no-way-labs
- License: mit
- Created: 2026-02-16T18:09:17.000Z (5 months ago)
- Default Branch: main
- Last Pushed: 2026-07-03T17:40:26.000Z (2 days ago)
- Last Synced: 2026-07-03T19:25:19.191Z (1 day ago)
- Topics: compiler, compiler-optimization, functional-programming, language-design, linear-types, ocaml, programming-language, stream-fusion, systems-programming, zig
- Language: OCaml
- Size: 452 KB
- Stars: 0
- Watchers: 0
- Forks: 0
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Mo
**Pure functional code. Imperative performance.**
Mo is a strict functional language where you write clean, compositional code and the compiler generates efficient imperative output. No ownership annotations. No garbage collector.
> **Paper:** [Mo: Pure Functional Code, Imperative Performance](docs/paper/mo_abstract.pdf)
---
## The result
On five non-pipeline benchmarks, Mo runs at roughly Zig-comparable time (~1x) with lower measured peak RSS.
| Benchmark | Pattern | vs Zig (Time) | vs Zig (Memory) | Note |
|-----------|---------|:---:|:---:|------|
| Edit Distance | 2D dynamic programming | ~1x | **0.97x** | Same 2-row algorithm both sides |
| Graph BFS | Visited set, queue | ~1x | **0.82x** | Zig baseline being strengthened |
| Red-Black Tree | Balanced tree, rebalancing | ~1x | **0.90x** | Mo delegates to a native runtime tree |
| LRU Cache | HashMap + linked list | ~1x | **0.92x** | Same delegation; eviction semantics differ slightly |
| Regex NFA | State machine simulation | — | — | Under repair: current Mo matcher lacks epsilon closure |
These aren't pipelines. They're graph traversals, dynamic programming, pointer-heavy trees, coordinated data structures, and state machines --- the cases that have historically been hard for functional languages.
**Caveats we're actively addressing:** the two sides currently use different allocators (malloc vs Zig's GPA), Mo-emitted code does not yet free memory (which flatters peak RSS for short-lived processes), and the benchmark runner does not yet assert output equality. See [docs/guide/generalization_benchmarks.md](docs/guide/generalization_benchmarks.md) for methodology. The strongest measured result is Mo-vs-Mo: the compiler's swap-buffer and hoisting passes automatically reduce per-iteration allocation by up to 752x on naively written DP folds.
---
## Quick start
**Prerequisites:** OCaml (for the compiler), Zig 0.15+ (for the runtime)
```bash
# Build the compiler
./src/compiler/build.sh
# Compile and run an example
./src/compiler/moc examples/fib.mo
zig run examples/fib.zig
```
---
## What it looks like
```ml
-- Fibonacci
letrec fib = \n ->
if lt n 2 then n
else add (fib (sub n 1)) (fib (sub n 2))
in fib 35
```
```ml
-- Pipeline fusion: compiles to a single loop, zero intermediate arrays
let sum_doubled = \xs ->
fold (\acc x -> add acc x) 0 (map (\x -> mul x 2) xs)
in
sum_doubled (collect (range 0 10))
```
```ml
-- O(log n) red-black tree with pure functional semantics
let tree = treemap_put tree key value in
let (tree, result) = treemap_get tree key in
```
```ml
-- Edit distance: compiler detects swap-buffer pattern,
-- allocates two buffers upfront instead of per-iteration
let result = fold (\(prev_row, curr_row) i ->
let new_row = compute_dp_row prev_row curr_row i in
(curr_row, new_row)
) (row0, row1) (range 0 num_rows)
```
---
## How it works
Three mechanisms close the gap between functional semantics and imperative efficiency:
**1. Linearity inference.** The compiler infers when values are used exactly once, enabling in-place mutation --- without user-written ownership annotations. Unlike Rust, where developers explicitly manage lifetimes, Mo infers linearity from usage. The current analysis has known soundness gaps that are being closed; a runtime uniqueness check with copy fallback is planned as the safety net.
**2. Stateful pattern fusion.** Common patterns (swap-buffer, buffer hoisting, prefix slices) are detected and optimized automatically. The compiler extends fusion beyond pipelines to stateful folds.
**3. Opaque linear handles.** When algorithmic complexity matters (O(log n) trees, O(1) caches), handles provide efficient mutable data structures with pure functional semantics.
```
Pure Functional Code
fold, map, filter, update_inplace, treemap_*, lru_*, ...
|
v
OCaml Compiler
Analysis + Optimization Engine
(linearity inference, pattern fusion, stream fusion;
type checking currently via the Zig backend)
|
v
Generated Zig Code
In-place mutation, efficient data structures, zero-copy
```
---
## Project structure
```
mo/
src/
compiler/ # OCaml compiler (lexer, parser, analysis, optimizer, codegen)
runtime/ # Zig runtime (allocators, arrays, streams)
lib/
std/ # Standard library
examples/ # Example programs (.mo files)
docs/
paper/ # Research paper (LaTeX + PDF)
guide/ # Language guide, spec, optimization docs
```
---
## Documentation
| Document | What it covers |
|----------|----------------|
| [Paper (PDF)](docs/paper/mo_abstract.pdf) | Research paper with benchmarks and design |
| [Language Guide](docs/guide/language_guide.md) | Syntax, semantics, and practical reference |
| [Language Spec](docs/guide/spec.md) | Full specification |
| [Opaque Linear Handles](docs/guide/opaque_linear_handles.md) | HashMap, TreeMap, LRU, Deque APIs |
| [Stateful Pattern Fusion](docs/guide/stateful_pattern_fusion.md) | Compiler optimization passes |
| [Benchmarks](docs/guide/generalization_benchmarks.md) | Methodology and results |
---
## Status
Mo is an early-stage research prototype exploring whether pure functional code can achieve systems-level performance. The compiler runs and the code is here to try; the benchmark suite and the linearity analysis are under active repair, and claims above should be read with the stated caveats.
What exists:
- Working compiler (OCaml) targeting Zig, fast happy-path builds
- Stream fusion, linearity heuristics, stateful pattern fusion (swap-buffer and hoisting passes)
- Opaque linear handles (HashMap, TreeMap, LRU, Deque) backed by native runtime implementations
- Examples and a small standard library
What's next (in order):
- Benchmark suite repair (regex epsilon closure, stronger Zig baselines, matched allocators, output-equality checks)
- A sound, gated linearity analysis with a runtime uniqueness fallback
- A real type checker and name resolution in the Mo frontend
- Formalization of the rolling-buffer inference (the core research contribution)
---
## License
- Code (compiler, runtime, standard library, examples): [MIT](LICENSE) — No Way Labs
- Paper (`docs/paper/`): [CC BY 4.0](docs/paper/LICENSE)
---
*Mo: where functional programming meets systems performance.*