Scheme: Notes and Examples
Table of Contents
1. Scheme
1.1. Getting started
brew install chezscheme guile
1.2. 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)));
1.3. 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))
1.4. Map Reduce
(define (sh/wal/square n)
(* n n))
;; (define (filter predicate sequence))
(map sh/wal/square (list 1 2 3 4 5))
1.5. Numbers
(define (sh/wal/pct numer denom)
(exact->inexact (* 100 (/ numer denom))))
(sh/wal/pct 1111 3333)
1.6. 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)
1.7. Conditionals
(define (sh/wal/even? n)
(cond
((< n 2) (= 0 n))
(else
(sh/wal/even? (- n 2)))))
(sh/wal/even? 1000)
1.8. Recursion
(define sh/wal/fact
(lambda (n)
(if
(= 0 n)
1
(* n (sh/wal/fact (- n 1))))))
(sh/wal/fact 10)
1.9. 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)
1.10. 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)
1.11. Modules
1.12. Abstractions
2. 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.
2.1. 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.
2.2. 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.
2.3. 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.
2.4. 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.
2.5. 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)"
2.6. 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];
}
3. 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
4. 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}
}