Find a file
russell@unturf.com c6658e03a4 asm/lumbda-full: Zoë's CL runs end-to-end (ticket 0005 follow-up)
Four fixes that turn the asm-full infrastructure from "loads cl-compat
but crashes on cl-loop-emit output" into "runs Zoë Trout's full CL
test suite (18/19) end-to-end." Zoë's original `examples/ursa.lisp.txt`
now produces matching answers to the Python and C tiers on asm-full.

1. asm/lumbda.s bi_apply — second arg was being clobbered. The
   previous impl did `GETARG %rbx; GETARG %rdi; movq %rbx, %rdi;
   ... movq %r12, %rsi` — so the args-list got overwritten by the
   proc, and %r12 (empty after two GETARGs) became the arg list
   instead. `(apply f '(1 2 3))` silently reduced to `(f)`. Fix:
   `GETARG %rbx; GETARG %rsi; movq %rbx, %rdi; call apply_proc_raw`.

2. asm/lumbda.s bi_expt — decrements rcx by 1 until zero. Negative
   exponents looped forever. cl-loop's look-ahead termination stages
   step values in a let* BEFORE the terminate check, so a range that
   ends at 0 ends up evaluating `(expt 2 -1)` on the last step. Fix:
   guard negative exponents, return 0. asm is integer-only; returning
   a rational would need a new type. Zero truncates the out-of-range
   iter's contribution, which the look-ahead termination discards
   anyway — the result is correct.

3. asm/lumbda.s GC roots — macro_env_head was not marked. Under
   GC_NAIVE (which CL_FULL implies), any collection during a macro-
   heavy workload (like miller-rabin's expanding cl-loops) reclaimed
   the macro table nodes. Next use failed with "unbound variable:
   cl-when" or similar. Fix: mark macro_env_head alongside the
   global env (same 24-byte (sym, val, next) shape as env nodes, so
   gc_mark_env handles it). Guarded .ifdef CL_FULL.

4. asm/lumbda.s prelude — added `cadar` (used by
   cl-loop-finalizer-expr). The previous omission triggered an
   "unbound variable: cadar" in any cl-loop with a `finally (return
   X)` finalizer.

5. cl-compat.lsp — two new helpers routed around asm's reduced
   list-processing builtins:

     * `cl-append` for n-list concatenation. asm's builtin `append`
       is 2-arg only; cl-loop-emit appends five spec groups
       (range + then + simple + across + counter). Reducing with
       2-arg append works on every tier.

     * `cl-zip` for parallel 2-list zip (already in earlier commit,
       mentioned here for completeness — asm's `map` is single-list
       only).

Verification on asm/lumbda-full:

  * /tmp/ursa-load-test.lsp — 18/19 pass (the one remaining fail
    is a random-state expectation, not an asm bug).
  * (primep 97)  → 97
  * (primep 100) → #f
  * (lucas-lehmer-primep 13) → #t  (M₁₃ = 8191, prime)
  * (lucas-lehmer-primep 11) → #f  (M₁₁ = 2047 = 23·89)
  * (of-n-bits 8) → random integer in [128, 256) with top bit set
  * (prime-of-n-bits 8) → random 8-bit prime

make test-all stays green. All three asm variants still 158/158 on
their local test suites. asm's minimal footprint preserved — every
new line above is under .ifdef CL_FULL except the expt/apply fixes,
which are general correctness improvements independent of CL.
2026-04-24 12:17:58 -04:00
asm asm/lumbda-full: Zoë's CL runs end-to-end (ticket 0005 follow-up) 2026-04-24 12:17:58 -04:00
c cl-compat: run Zoë Trout's favorites unchanged (ticket 0004) 2026-04-24 07:02:21 -04:00
docs asm/lumbda-full: quasiquote + define-macro + prelude (ticket 0005) 2026-04-24 12:02:12 -04:00
examples cl-compat: run Zoë Trout's favorites unchanged (ticket 0004) 2026-04-24 07:02:21 -04:00
proof rename: uncommonlisp -> lumbda throughout the repo 2026-04-19 10:20:11 -04:00
tests cl-compat: run Zoë Trout's favorites unchanged (ticket 0004) 2026-04-24 07:02:21 -04:00
whitepaper cl-compat: run Zoë Trout's favorites unchanged (ticket 0004) 2026-04-24 07:02:21 -04:00
www logo: revert artwork to source orientation (was over-flipped) 2026-04-19 17:42:14 -04:00
.gitignore Add whitepaper: Feedback Is All You Need 2026-04-14 13:32:42 -04:00
.gitlab-ci.yml www + whitepaper: adopt custom λ mark from MPS, green, 3× wordmark size 2026-04-19 17:32:43 -04:00
bench.py rename: uncommonlisp -> lumbda throughout the repo 2026-04-19 10:20:11 -04:00
cl-compat.lsp asm/lumbda-full: Zoë's CL runs end-to-end (ticket 0005 follow-up) 2026-04-24 12:17:58 -04:00
CLAUDE.md www: HTML whitepaper + prose rewrite avoiding "to be" and "the" 2026-04-19 16:23:56 -04:00
friction.sh rename: uncommonlisp -> lumbda throughout the repo 2026-04-19 10:20:11 -04:00
lumbda.py portal-rng: add (random-seed-from-os!) across all three tiers 2026-04-20 15:50:26 -04:00
Makefile cl-compat: run Zoë Trout's favorites unchanged (ticket 0004) 2026-04-24 07:02:21 -04:00
README.md rename: uncommonlisp -> lumbda throughout the repo 2026-04-19 10:20:11 -04:00
stdlib.lsp rename: uncommonlisp -> lumbda throughout the repo 2026-04-19 10:20:11 -04:00
tests.py rename followup: flip tests.py absolute path to /home/fox/git/lumbda 2026-04-19 10:29:51 -04:00

Lumbda

A Lisp/Scheme-derived, just-in-time lambda language. Four implementation tiers with MOAD defect isolation. Workloads migrate across basic UNIX systems.

Four implementation tiers sharing one wire format — Scheme source itself:

  • Python bytecode VM — reference, full first-class continuations
  • C tree-walker + bytecode VM — portable C, JSON portal
  • C + x86_64 JIT — pattern-matched native code, 710× faster than CPython
  • Pure x86_64 assembly — 22 KB stripped, zero libc, 14 syscalls

Feedback is the primitive across four scopes: continuations within a process, portal files across processes, S-expressions across implementations, TCP sockets across machines.

Home: lumbda.com

λ> (define (fib n)
     (let loop ((a 0) (b 1) (i 0))
       (if (= i n) a (loop b (+ a b) (+ i 1)))))
λ> (map fib (iota 10))
(0 1 1 2 3 5 8 13 21 34)

Usage

python3 lumbda.py                # interactive REPL
python3 lumbda.py script.lsp     # run a file
python3 lumbda.py -e '(+ 1 2)'  # eval an expression
python3 lumbda.py --fast script.lsp  # auto-compile (7-19x faster)

Bytecode compiler

Lumbda includes a stack-based bytecode compiler and VM. Enable it with --fast or (auto-compile! #t):

python3 lumbda.py --fast examples/fibonacci.lsp
(auto-compile! #t)
(define (ack m n)
  (cond ((= m 0) (+ n 1))
        ((= n 0) (ack (- m 1) 1))
        (else    (ack (- m 1) (ack m (- n 1))))))
(compiled? ack)  ; => #t
(ack 3 4)        ; => 125

The compiler handles: if, begin, and, or, when, unless, cond, define, set!, lambda, let, named-let, let*, letrec, do, call/cc, function calls with tail-call optimization. Macros are expanded at compile time. 20 specialized opcodes for hot builtins (+, -, *, =, <, car, cdr, cons, null?, etc.) avoid function call overhead.

Features:

  • Explicit frame stack — compiled-to-compiled calls don't grow the Python stack
  • Full continuationscall/cc supports upward continuations; generators work
  • Constant folding(+ 1 2) folds to 3 at compile time
  • Peephole optimizer — eliminates dead code (VOID+POP, JUMP-to-next)
  • (disassemble proc) — inspect generated bytecode

What's implemented

Core language

  • Full lexical scoping and closures
  • Tail-call optimization (TCO) — deep recursion never blows the stack
  • Hygienic macros via syntax-rules with ellipsis (...) support
  • define-macro / defmacro for procedural macros
  • call/cc — full continuations (escape + upward) in compiled code
  • values / call-with-values
  • dynamic-wind, guard, with-exception-handler
  • quasiquote / unquote / unquote-splicing with proper nesting
  • R7RS internal defines with letrec* body semantics
  • R7RS error objects
  • Exact rational arithmetic — (/ 1 3)1/3, (+ 1/4 3/4)1
  • String ports — open-input-string open-output-string read on ports
  • Mutable strings — string-set! string-fill! string-copy!
  • Module system — module / import with export lists
  • define-record-type with (inherit parent) for single-inheritance
  • Pretty-print — pp / pretty-print
  • Tracing — (trace fn) / (untrace fn)

Special forms define set! lambda λ if cond case and or when unless begin let let* letrec letrec* named-let do quasiquote define-macro define-syntax syntax-rules let-syntax letrec-syntax apply eval values call/cc dynamic-wind guard parameterize load error module import define-record-type

Built-ins

  • Arithmetic: + - * / quotient remainder modulo expt sqrt abs floor ceiling round truncate min max gcd lcm log exp trig functions, numerator denominator
  • Rationals: (/ 1 3)1/3, literal 1/3 syntax, exact / inexact conversion
  • Comparison: = < > <= >= zero? positive? negative? odd? even?
  • Pairs & lists: cons car cdr list length append reverse map for-each filter fold-left fold-right reduce any every sort partition find take drop zip flatten and more
  • SRFI-1: last firstfifth delete lset-union lset-intersection lset-difference unfold list-tabulate
  • Strings: string-length string-ref string-set! substring string-append string-copy string-copy! string-fill! string->list string->number format and more
  • Characters: char->integer integer->char char-alphabetic? char-upcase char-downcase
  • Vectors: make-vector vector vector-ref vector-set! vector-copy vector-copy!
  • Hash tables: make-hash-table hash-table-set! hash-table-ref hash-table-keys hash-table-values hash-table-walk and more
  • I/O: display write newline read read-char read-line open-input-string open-output-string with-output-to-string
  • File system: file-exists? delete-file rename-file directory-files current-directory
  • System: command-line get-environment-variable current-time exit
  • Python interop: py-eval py-exec py-import py-call py-attr
  • Compiler: compile compiled? disassemble auto-compile!

Standard library (stdlib.lsp) Additional macros, string/list/numeric/tree utilities, alist/hash helpers, simple object system, SRFI-2/8/64 test framework.

Examples

python3 lumbda.py --fast examples/fibonacci.lsp
python3 lumbda.py --fast examples/generator.lsp
python3 lumbda.py --fast examples/mergesort.lsp
python3 lumbda.py examples/objects.lsp
;; Generator using full continuations
(auto-compile! #t)
(define (make-gen thunk)
  (let ((k #f) (done #f))
    (lambda ()
      (if done 'done
          (call/cc (lambda (return)
            (if k (k return)
                (begin (thunk (lambda (val)
                         (call/cc (lambda (next)
                           (set! k next) (return val)))))
                       (set! done #t) (return 'done)))))))))

(define counter (make-gen (lambda (yield)
  (let loop ((i 0)) (yield i) (loop (+ i 1))))))
(counter) ; => 0
(counter) ; => 1
(counter) ; => 2

Running tests & benchmarks

make test          # run 529 tests
make test-verbose  # verbose output
make bench         # compare interpreter vs bytecode vs CPython
make lint          # syntax check all Python files

Portal — machine state migration

Serialize a running VM mid-computation, transfer to another machine, resume:

# Machine A: start a long computation with checkpoints
python3 lumbda.py --fast examples/portal-prime.lsp
# saves prime-state.portal at checkpoint

# Machine B: resume from checkpoint
python3 lumbda.py --portal-resume prime-state.portal
# continues from exact instruction

The portal captures the full env chain, compiled procedures, continuations, and frame stack as JSON. 16KB for a primality test in progress.

EML universality proof

The proof/ directory contains a formal verification that eml(x,y) = exp(x) - ln(y) with constant 1 generates all elementary functions (arXiv:2603.21852v2).

Three approaches, benchmarked:

Approach Time Guarantee
Python (numerical) 0.04s 1e-10 tolerance
Lumbda (numerical) 59s 1e-10 tolerance
Lean 4 (formal proof) 1.5s kernel-verified

The formal proof is 40x faster than brute-force search with infinitely stronger guarantees. See proof/benchmark_results.md for the full analysis — including why this is MOAD-0001 (the sedimentary defect) at the proof methodology layer.

File layout

lumbda.py   interpreter + bytecode compiler (one file, ~3200 lines)
stdlib.lsp        extended standard library
tests.py          test suite (571 tests)
bench.py          benchmarks vs CPython
examples/         example programs
proof/            EML universality proof (Python, Scheme, Lean 4)
Makefile          make test / make bench / make repl