Recursion at the limit of the machine.

muhan.dev is a runtime, a standard library, and a documentation portal for engineers building infinite-scale systems on top of finite hardware. Tail calls, fixed points, lazy streams — first-class.

last edit2 hours ago authors@haewon · @jisoo · @aram est. read7 min

§ Overview

The runtime treats recursion as the primary control flow primitive. Iteration is a special case of a tail call. Memory is a special case of a stream. Time is a special case of a lazy fold over an unbounded sequence.

The core API exposes a small set of combinators that compose into arbitrarily complex recursive structures without stack growth. Implementations are verified at compile time using a dependent type checker that has its own dedicated chapter.

NOTE
All examples in this portal are runnable in-place. Press R on any code block to evaluate it against the local sandbox runtime.

§ Installation

Three supported channels: stable, edge, and proof-carrying. The stable channel is recommended for production deployments.

1$ curl -fsSL https://muhan.dev/install.sh | sh2$ muhan init --scale=infinite --strict3# resolves the project graph in O(log n) ammortized4$ muhan verify

§ Fixed Points

A fixed point of f is any x such that f(x) = x. The standard library exposes fix, the least fixed-point combinator over a bottom-pointed lattice.

fix(f)
n ∈ ℕ fn(⊥)

The supremum is computed lazily; in practice the runtime stops at the first index where two successive iterates are bisimilar under the chosen equivalence.

1import { fix, memo } from "@muhan/core";23// classic factorial as the fixed point of an open recursion.4const factorial = fix(self => (n: bigint): bigint =>5  n <= 1n ? 1n : n * self(n - 1n)6);78const fib = memo(fix(self => (n: bigint): bigint =>9  n < 2n ? n : self(n - 1n) + self(n - 2n)10));1112factorial(42n);  // 1405006117752879898543142606244511569936384000000000n13fib(10000n); // computed in 11 ms with memoization

§ Lazy Streams

Streams are codata: corecursively defined, observed by demand. The standard library models the natural numbers, the primes, and the digits of π as ordinary stream values.

1import { stream } from "@muhan/core";23const naturals = stream.iterate(2n, n => n + 1n);45const sieve = (s) => s.unfold(({ head, rest }) => ({6  value: head,7  next:  sieve(rest.filter(x => x % head !== 0n))8}));910const primes = sieve(naturals);11primes.take(10); // [2,3,5,7,11,13,17,19,23,29]
1import { cf } from "@muhan/numerics";23// continued-fraction expansion of pi.4const pi = cf.brouncker();56pi.digits(12);7// "3.141592653589"89pi.precision(10_000)10  .at(9999); // 7

§ Algorithm Visualisation

Each documentation page can embed live algorithm visualisations. The block below traces a depth-first walk of a recursive call tree as it unfolds.

depth-first call trace · fib(7)
active memo hit leaf
step 0 / 0 depth 0

§ Reference Tables

Selected combinators from @muhan/core. Full reference under reference/api.md.

symbol
type
complexity
notes
fix
(a → a) → a
O(d)
least fixed point
memo
(a → b) → a → b
O(1)
structural cache
stream
() → Stream a
O(1)
codata constructor
trampoline
Step a → a
O(n)
stack-safe
unfold
(s → (a, s)) → Stream a
O(1)
corecursion

§ Recent Changes

  • added stream.zipLazy for non-aligned codata. v8.∞.0
  • fixed memoisation table now releases under bisimilarity equivalence. v8.7.4
  • break fix no longer accepts thunks; use delay. v8.7.0
  • added cantor-set generator under numerics/cantor. v8.6.2