Wok
Frontier control flow. Deterministic by construction.
Wok is a small ML-family language where the compiler erases reference counts at compile time, so pure functions mutate in place. Lifetimes are traced by one-shot continuations; effects are handled, not stacked. A glue language — not a replacement for your general-purpose stack.
Built for mission critical applications.
- Small by design, designed for easy integration
- We have designed Wok to work great alongside your C stack. Wok serves the control flow logic, with verified model and specialised design runtime.
- The Wok reclamation model
- No garbage collector. The compiler tracks every value’s lifetime itself — so when you transform data you uniquely own, the old cell becomes the new cell, in place. No allocation, no churn.
- One-shot continuations
- An effect handler can pause the program, step aside, then resume from where it left off. In wok, that resume happens at most once — enforced at compile time. That guarantee lets the compiler track every value’s lifetime for you — no lifetime annotations, no manual borrowing.
- No value restriction
- Because a continuation resumes at most once, it can’t re-observe captured state at a different type. The unsoundness that forces ML languages to restrict polymorphic values never arises — so Wok drops the value restriction entirely.
- Algebraic effect handlers
- Write orthogonal effects without monad transformers. Composable, and natural to read.
- Relational fixity
- Operator precedence is relational, not numeric — you declare fixity * left tighter than + instead of memorizing a precedence table. Ordering stays readable as the language grows.
The Wok discipline, in code.
The Wok reclamation model
-- Each Cons shell from the input spine is reused in place to build -- the accumulator. Net spine allocation: zero. data List = Nil | Cons U64 List rev : List -> List -> List rev acc xs = case xs of Nil -> acc Cons x xx -> rev (Cons x acc) xx main = rev Nil (Cons 1 (Cons 2 (Cons 3 Nil)))
A pure transform. Each consumed cell is reborn as its successor — no GC, no allocation.
Algebraic effect handlers
-- The State effect and its runner. The handler threads state through -- every get/set; the value arm returns (result, finalState). effect State s = { get : s, set : s -> () } state : s -> (() -> a with State s + eff e) -> (a, s) with eff e state i c = with State { s = i ; get -> s ; set x k -> k x () ; v -> (v, s) } c () -- Using it: state is threaded implicitly, no explicit parameter. main : (U64, U64) main = with state 100 in let a = State.get in let b = State.set (a + 5) in State.get
State, exceptions, readers, generators — all one mechanism. No monad transformers.
JIT FFI to C
foreign module Libc "c" free "free" where owned strndup : Bytes -> U64 -> Bytes with IO -- Calls libc's strndup directly. The `owned` marker hands Wok full -- lifetime control of the returned buffer; Wok frees it at rc 0. main = Libc.strndup (fromList [1, 2, 3, 4]) 2
Real C calls, with explicit borrowership at the boundary. Wok owns what owned returns.
Get wokup.
We host a version manager for the compiler suite — one line to install.
Experimental v0.1
On the road: a richer C integration so Wok can hand memory to and receive it from external libraries safely; arrays that live directly in C for predictable performance; and the long-term goal of bootstrapping — writing the Wok compiler in Wok itself.