Scheme: Notes and Examples
Table of Contents
Scheme
Getting started
brew install chezscheme guile
Pairs
(define (sh/wal/pair f r) (lambda (op) (op f r))) (define (sh/wal/first p) (p (lambda (f r) f))) (define (sh/wal/rest p) (p (lambda (f r) r))) (sh/wal/first (sh/wal/rest (sh/wal/pair 1 (sh/wal/pair 2 (sh/wal/pair 3 0)))))
const pair = (f, r) => (op) => op(f, r); const first = (p) => p((f, r) => f); const rest = (p) => p((f, r) => r); console.log(first(pair(1, 2)));
Lists
(define (sh/wal/accumulate op initial sequence) "Reduce a list to another structure" (if (null? sequence) initial (op (car sequence) (sh/wal/accumulate op initial (cdr sequence))))) (sh/wal/accumulate + 0 (list 1 2 3 4 5))
Map Reduce
(define (sh/wal/square n) (* n n)) ;; (define (filter predicate sequence)) (map sh/wal/square (list 1 2 3 4 5))
Numbers
(define (sh/wal/pct numer denom) (exact->inexact (* 100 (/ numer denom)))) (sh/wal/pct 1111 3333)
Functions
(define sh/wal/fib (lambda (n) (if (or (= 0 n) (= 1 n)) n (+ sh/wal/fib(- 1 n) fib(- 2 n))))) (sh/wal/fib 2)
Conditionals
(define (sh/wal/even? n) (cond ((< n 2) (= 0 n)) (else (sh/wal/even? (- n 2))))) (sh/wal/even? 1000)
Recursion
(define sh/wal/fact (lambda (n) (if (= 0 n) 1 (* n (sh/wal/fact (- n 1)))))) (sh/wal/fact 10)
Math
(define (sh/wal/limit n) (* 2 (floor (sqrt n)))) (sh/wal/limit 1000)
(define (sh/wal/gcd a b) (cond ((= a b) a) ((> a b) (sh/wal/gcd (- a b) b)) ((< a b) (sh/wal/gcd a (- b a))))) (sh/wal/gcd 120 35)
Closures
(define a 5.3) (define b 4.7) (define c 2.8) (define (sh/wal/area a b c) (let ((s (/ (+ a b c) 2))) (sqrt (* s (- s a) (- s b) (- s c))))) (sh/wal/area a b c)
Modules
Abstractions
2026 Review
A retrospective on where Scheme implementations stand in early 2026, with particular attention to R7RS standardization progress, tooling maturity, and emerging use in agentic/tool-use contexts.
Guile 3.0.10+ (2025–2026)
GNU Guile 3.0.x continued to ship incremental releases through 2025 into 2026. The headline win for this series is the JIT compiler landed in 3.0.0 (2020) finally reaching production stability: tail-call elimination across the JIT boundary, improved inlining heuristics, and better profiling support. Key milestones in the 3.0.9–3.0.10+ window:
- Baseline JIT now active by default on x86-64 and aarch64.
guildtool improvements: better dependency tracking for compiled.goartifacts.- Cleaner POSIX interface coverage in
(ice-9 popen)and(ice-9 ftw). - Ongoing GC tuning; the Boehm GC dependency is a persistent pain point for embedding scenarios.
R7RS-small compliance remains high: Guile passes the large majority of
the R7RS test suite. The outstanding gap areas are tail-position
semantics in define-record-type and some edge cases in
parameterize / dynamic-wind interaction.
Chez Scheme and the Racket CS Backend
Chez Scheme (now developed openly at github.com/cisco/ChezScheme) continues to set the performance bar for Scheme implementations. Notable 2025–2026 developments:
- Racket's CS backend (built on Chez) is now the default for
racketdistributions; the old expander/VM is no longer the recommended path. - Chez added initial support for R7RS library syntax, closing a long- standing compatibility gap with community SRFIs.
- Cross-compilation targets expanded:
riscv64support landed; ARM Cortex-M work-in-progress.
The Chez/Racket-CS combination gives the ecosystem an unusually capable implementation that combines ahead-of-time native compilation with a mature macro expander and module system.
R7RS-large Progress and SRFI Adoption
R7RS-large (the "Red Edition" successor to R7RS-small) defines a standard library via a curated set of SRFIs. As of 2026:
| SRFI | Topic | Adoption |
|---|---|---|
| 1 | List library | Universal (all major implementations) |
| 9 | Record types | Universal |
| 13 | String library | Guile, Chibi, Chicken, Gambit |
| 14 | Character sets | Guile, Chibi, Chicken |
| 45 | Lazy evaluation | Guile, Chibi, Chicken, Gambit, Chez |
| 69 | Hash tables | Guile (native), Chibi, Chicken |
| 106 | Basic socket interface | Chicken, Gambit; Guile (partial) |
| 133 | Vector library | Most R7RS-small implementations |
| 158 | Generators and accumulators | Chibi, Chicken, Gambit |
| 193 | Command line | Chibi; Guile (partial) |
The R7RS-large editors' group continues to publish ballot documents. The "Red Edition" scope is largely stable; the focus has shifted to implementation uptake rather than further specification changes.
Scheme in the Agent Era
Scheme has seen modest but real uptake in the emerging agentic/tool-use space, driven primarily by Guile's role as the extension language for GNU projects and Racket's strong macro/DSL story.
- Guile as an MCP substrate: Several experimental projects embed Guile as a sandboxed evaluation layer in Model Context Protocol (MCP) servers. The appeal is Scheme's homoiconicity — tool definitions are data, and tool results can be manipulated as first-class values.
- Racket for DSL agents: Racket's macro system makes it natural to define domain-specific tool languages; at least two published agentic frameworks (one from a university group, one from a startup) expose Racket-based tool-definition languages.
- Chicken Scheme on edge: Chicken's native-code compiler and small runtime footprint make it attractive for running lightweight inference scaffolding on constrained devices.
- Babashka influence: While Babashka is Clojure-based, its success in scripting has renewed interest in Guile and Gambit as portable Scheme scripting runtimes — fast startup, small binary, rich POSIX access.
No major MCP SDK for Scheme exists as of April 2026; the closest is an unofficial Guile binding to the MCP JSON-RPC protocol, maintained by the community at codeberg.org/guile-mcp.
Guile on FreeBSD
FreeBSD (the platform this site runs on) ships Guile in the ports tree
under lang/guile3. The story is workable but requires attention:
# Install Guile 3 on FreeBSD via pkg pkg install guile3 # Or from ports (gives configure control) # cd /usr/ports/lang/guile3 && make install clean # Verify installation guile3 --version # Run a quick smoke test guile3 -c "(display (+ 1 2)) (newline)"
Known friction points on FreeBSD as of 2026:
- The port links against Boehm-GC from
devel/boehm-gc. On FreeBSD 15.0-RELEASE this works cleanly, but pinning the port version matters when doing binary packages across major releases. - JIT support on FreeBSD/amd64 is present but requires
W^X-compliant memory allocation; the Guile port patches this correctly. guild compilecan be slow on first build due to the bootstrapping pass; subsequent incremental compiles are fast.- The
BEADS_NO_DAEMON=1pattern (used in this repo's worktrees) pairs well with Guile scripting since both avoid long-lived daemon processes.
Recommended approach for Guile-based tooling on this FreeBSD host:
# Add to ~/.bashrc or ~/.zshrc export GUILE_LOAD_PATH="${HOME}/.local/share/guile/site/3.0:${GUILE_LOAD_PATH}" export GUILE_COMPILED_PATH="${HOME}/.cache/guile/ccache/3.0-LE-8-4.4:${GUILE_COMPILED_PATH}" # Confirm Guile sees local site directory guile3 -c "(for-each (lambda (p) (display p) (newline)) %load-path)"
R7RS Implementation Landscape
digraph scheme_landscape { rankdir=LR; node [fontname="Helvetica", shape=box, style=filled]; // Standards r5rs [label="R5RS (1998)", fillcolor="#e8f4e8", shape=ellipse]; r7rs_small [label="R7RS-small (2013)", fillcolor="#b8deb8", shape=ellipse]; r7rs_large [label="R7RS-large\n(Red Edition, in progress)", fillcolor="#88c088", shape=ellipse]; // R7RS-small implementations guile [label="Guile 3.0.10+\n(GNU/FreeBSD)", fillcolor="#cce0ff"]; chez [label="Chez Scheme\n(+ Racket CS)", fillcolor="#cce0ff"]; chibi [label="Chibi-Scheme\n(embeddable)", fillcolor="#cce0ff"]; chicken [label="Chicken 5\n(native code)", fillcolor="#cce0ff"]; gambit [label="Gambit\n(C/JS targets)", fillcolor="#cce0ff"]; kawa [label="Kawa\n(JVM)", fillcolor="#ddd0ff"]; // SRFI nodes (R7RS-large building blocks) srfi1 [label="SRFI-1\nList library", fillcolor="#fff0cc", shape=note]; srfi9 [label="SRFI-9\nRecord types", fillcolor="#fff0cc", shape=note]; srfi69 [label="SRFI-69\nHash tables", fillcolor="#fff0cc", shape=note]; srfi133 [label="SRFI-133\nVectors", fillcolor="#fff0cc", shape=note]; srfi158 [label="SRFI-158\nGenerators", fillcolor="#fff0cc", shape=note]; // Standard lineage r5rs -> r7rs_small; r7rs_small -> r7rs_large; // R7RS-small compliance r7rs_small -> guile; r7rs_small -> chez; r7rs_small -> chibi; r7rs_small -> chicken; r7rs_small -> gambit; r7rs_small -> kawa; // R7RS-large SRFI adoption r7rs_large -> srfi1; r7rs_large -> srfi9; r7rs_large -> srfi69; r7rs_large -> srfi133; r7rs_large -> srfi158; // Implementation SRFI support edges (selected) srfi9 -> guile [style=dashed, label="native"]; srfi9 -> chibi [style=dashed, label="native"]; srfi9 -> chicken [style=dashed, label="native"]; srfi9 -> gambit [style=dashed, label="native"]; srfi1 -> guile [style=dashed]; srfi1 -> chibi [style=dashed]; srfi69 -> guile [style=dashed, label="native"]; srfi158 -> chibi [style=dashed]; srfi158 -> chicken [style=dashed]; }
Source
;; Pairs (define sh/wal/pair (lambda (f r) (lambda (op) (op f r)))) (define sh/wal/first (lambda (p) (p (lambda (f r) f)))) (define sh/wal/rest (lambda (p) (p (lambda (f r) r)))) ;; Lambda Calculus Style (define sh/wal/switch (lambda (f) (lambda (r) (lambda (op) ((op f) r))))) (define sh/wal/left (lambda (a) (lambda (b) a))) (define sh/wal/right (lambda (a) (lambda (b) b))) (sh/wal/right ((sh/wal/switch 1) 2)) (define sh/wal/true (lambda (a) (lambda (b) a))) (define sh/wal/false (lambda (a) (lambda (b) b))) (define sh/wal/not (lambda (x) ((x sh/wal/false) sh/wal/true))) (eq? (sh/wal/not sh/wal/true) sh/wal/false) (eq? (sh/wal/not (sh/wal/not sh/wal/true)) sh/wal/true) (eq? (sh/wal/not sh/wal/false) sh/wal/true) (define sh/wal/and (lambda (x) (lambda (y) ((x y) x)))) (define sh/wal/or (lambda (x) (lambda (y) ((x x) y)))) ;; Numbers (define sh/wal/gcd (lambda (a b) (cond ((= a b) a) ((> a b) (sh/wal/gcd (- a b) b)) ((< a b) (sh/wal/gcd a (- b a)))))) ;; Rational Numbers (define sh/wal/make-rat (lambda (n d) (sh/wal/pair n d))) (define sh/wal/numer0 (lambda (x) (sh/wal/first x))) (define sh/wal/denom0 (lambda (x) (sh/wal/rest x))) (define half (sh/wal/make-rat 1 2)) (sh/wal/numer0 half) (sh/wal/denom0 half) ;; TODO Map (define (sh/wal/map op sequence) "Reduce a list to another structure" (if (not (null? sequence)) (cons (op (car sequence)) (sh/wal/map op (cdr sequence))))) (define sh/wal/inc (lambda (n) (+ 1 n))) (sh/wal/map sh/wal/inc (list 1 2 3 4 5)) ;; Reduce (define (sh/wal/accumulate op initial sequence) "Reduce a list to another structure" (if (null? sequence) initial (op (car sequence) (sh/wal/accumulate op initial (cdr sequence))))) (sh/wal/accumulate + 0 (list 1 2 3 4 5)) ;; Types (define twenty-four-seven (sh/wal/make-rat 120 35)) (sh/wal/gcd (sh/wal/numer0 twenty-four-seven) (sh/wal/denom0 twenty-four-seven)) (define (sh/wal/numer x) (let ((g (sh/wal/gcd (sh/wal/first x) (sh/wal/rest x)))) (/ (sh/wal/first x) g))) (define (sh/wal/denom x) (let ((g (sh/wal/gcd (sh/wal/first x) (sh/wal/rest x)))) (/ (sh/wal/rest x) g))) (sh/wal/numer twenty-four-seven) (sh/wal/denom twenty-four-seven) ;; Sequences (define (sh/wal/list-ref items n) (if (= n 0) (sh/wal/first items) (sh/wal/list-ref (sh/wal/rest items) (- n 1)))) (define squares (sh/wal/pair 1 (sh/wal/pair 4 (sh/wal/pair 9 (sh/wal/pair 16 (sh/wal/pair 25 36)))))) (sh/wal/list-ref squares 3) ;; Trees
Reading
@book{10.5555/230223, author = {Friedman, Daniel P. and Felleisen, Matthias}, title = {The Little Schemer (4th Ed.)}, year = {1996}, isbn = {0262560992}, publisher = {MIT Press}, address = {Cambridge, MA, USA} } @book{10.5555/230222, author = {Friedman, Daniel P. and Felleisen, Matthias}, title = {The Seasoned Schemer}, year = {1996}, isbn = {026256100X}, publisher = {MIT Press}, address = {Cambridge, MA, USA} } @book{10.5555/547755, author = {Abelson, Harold and Sussman, Gerald J.}, title = {Structure and Interpretation of Computer Programs}, year = {1996}, isbn = {0262011530}, publisher = {MIT Press}, address = {Cambridge, MA, USA}, edition = {2nd} } @book{10.5555/1096473, author = {McCarthy, John}, title = {LISP 1.5 Programmer’s Manual}, year = {1962}, isbn = {0262130114}, publisher = {The MIT Press} }
