Two additions requested by fox: 1. Methodology is now explicit: GNU assembler (GAS, AT&T syntax), Intel Core i5-8350U 8th-gen mobile, Ubuntu 24.04, Linux 6.17, gcc 13.3, as 2.42, Python 3.12. Loopback TCP for all socket benchmarks. Same hardware across every benchmark in the paper. 2. §12 opens with the Lean EML proof as the rigor standard. The proof is 40× faster than the brute-force numerical verification it replaced — that speedup IS the MOAD-0001 story at the proof layer. We hold the implementations to the same bar: hot paths must be fast for a reason (hash / cache / O(1) invariant), not by benchmark luck; correctness must hold for a reason, not coincidence. The scanner is the second line; building with understanding is the first. Noted that the most recent scan found 18 HIGH MOAD- 0001 candidates in C — all inspected individually turn out to be false positives (bounded-depth ancestor walks, hash bucket chain walks already O(1) amortized, static 6-element tables, one-shot option parsing). The MOAD-0003 Python flags are scanner misfires on a non-ContextVar Env.set() method. New-work-introduced MOAD-0001 defects: zero. All defects fixed in this paper (intern_symbol, _define_record_type, bi_string_replace, _tokenize_lines, Env.lookup shortcut) were surfaced by other pressures — benchmarks, crashes, portal exchanges — not the scanner. |
||
|---|---|---|
| asm | ||
| c | ||
| docs | ||
| examples | ||
| proof | ||
| tests | ||
| whitepaper | ||
| .gitignore | ||
| bench.py | ||
| CLAUDE.md | ||
| friction.sh | ||
| Makefile | ||
| README.md | ||
| stdlib.lsp | ||
| tests.py | ||
| uncommonlisp.py | ||
uncommonlisp
A Scheme interpreter in one Python file, with a bytecode compiler.
λ> (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 uncommonlisp.py # interactive REPL
python3 uncommonlisp.py script.lsp # run a file
python3 uncommonlisp.py -e '(+ 1 2)' # eval an expression
python3 uncommonlisp.py --fast script.lsp # auto-compile (7-19x faster)
Bytecode compiler
uncommonlisp includes a stack-based bytecode compiler and VM. Enable it with --fast or (auto-compile! #t):
python3 uncommonlisp.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 continuations —
call/ccsupports upward continuations; generators work - Constant folding —
(+ 1 2)folds to3at 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-ruleswith ellipsis (...) support define-macro/defmacrofor procedural macroscall/cc— full continuations (escape + upward) in compiled codevalues/call-with-valuesdynamic-wind,guard,with-exception-handlerquasiquote/unquote/unquote-splicingwith 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-stringopen-output-stringreadon ports - Mutable strings —
string-set!string-fill!string-copy! - Module system —
module/importwith export lists define-record-typewith(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:
+-*/quotientremaindermoduloexptsqrtabsfloorceilingroundtruncateminmaxgcdlcmlogexptrig functions,numeratordenominator - Rationals:
(/ 1 3)→1/3, literal1/3syntax,exact/inexactconversion - Comparison:
=<><=>=zero?positive?negative?odd?even? - Pairs & lists:
conscarcdrlistlengthappendreversemapfor-eachfilterfold-leftfold-rightreduceanyeverysortpartitionfindtakedropzipflattenand more - SRFI-1:
lastfirst–fifthdeletelset-unionlset-intersectionlset-differenceunfoldlist-tabulate - Strings:
string-lengthstring-refstring-set!substringstring-appendstring-copystring-copy!string-fill!string->liststring->numberformatand more - Characters:
char->integerinteger->charchar-alphabetic?char-upcasechar-downcase - Vectors:
make-vectorvectorvector-refvector-set!vector-copyvector-copy! - Hash tables:
make-hash-tablehash-table-set!hash-table-refhash-table-keyshash-table-valueshash-table-walkand more - I/O:
displaywritenewlinereadread-charread-lineopen-input-stringopen-output-stringwith-output-to-string - File system:
file-exists?delete-filerename-filedirectory-filescurrent-directory - System:
command-lineget-environment-variablecurrent-timeexit - Python interop:
py-evalpy-execpy-importpy-callpy-attr - Compiler:
compilecompiled?disassembleauto-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 uncommonlisp.py --fast examples/fibonacci.lsp
python3 uncommonlisp.py --fast examples/generator.lsp
python3 uncommonlisp.py --fast examples/mergesort.lsp
python3 uncommonlisp.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 uncommonlisp.py --fast examples/portal-prime.lsp
# saves prime-state.portal at checkpoint
# Machine B: resume from checkpoint
python3 uncommonlisp.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 |
| uncommonlisp (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
uncommonlisp.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