Chapter 59 — 42 IS an AST
A substrate chapter — the kind where the code gets re-aligned with what we’d been pretending it already was.
The user, mid-conversation about a cache that needed HolonAST as
its key:
Atoms should only be able to hold HolonAST - we should make that a firm requirement
Then, a few exchanges later, sharpening:
in holon algebra - the atom is a holder of a concrete thing - that concrete thing can be an AST
And then the question that tipped the room over:
are these primitives just a most basic form on an AST?… the number 42 is an AST?
Right.
The inversion
Section titled “The inversion”The substrate had been carrying a contradiction. HolonAST::Atom
was parametric over arbitrary Rust — Arc<dyn Any + Send + Sync> —
so anything that fit in memory could be an atom payload. The
typeless escape hatch worked, technically, but it inverted Lisp’s
algebra. In Lisp, 42 IS an atom; the predicate (atom? 42) is
true because 42 is the simplest possible expression — a leaf. We
had built a substrate where 42 needed an Atom(...) wrapper to
become an atom, and the wrapper carried dyn Any, which meant the
substrate couldn’t hash its own atoms structurally.
What did that cost? Things you don’t see until you look:
HashMap<HolonAST, V>couldn’t compile.dyn Anydoesn’t implementHash. So no structural cache keys; engram libraries had to reach for SimHash (locality-preserving — the wrong tool for memoization).- An
AtomTypeRegistryhad to exist alongside the algebra, registering canonicalizers for every Rust type that might show up as an atom payload. The registry was the mechanism; the algebra carried the conceptual weight; they were separate systems pretending to be one. - The wat-lru shim had to panic on non-primitive keys, because the shim couldn’t see how to hash an arbitrary payload. A real feature was off-limits at the surface because the substrate hadn’t closed under itself.
Each of those was a workaround. None of them was the math.
Closing the algebra
Section titled “Closing the algebra”The recognition: a primitive IS an AST. The number 42 is the
simplest possible HolonAST — a leaf with no sub-terms. The boolean
true is an AST. The string "foo" is an AST. The keyword
:outcome is an AST. They have well-defined canonical encodings,
they participate in cosine the same way composites do, they
already produce vectors. The only thing missing was a Rust-level
acknowledgement that they belong to the algebra at the leaf level.
Eleven variants. Five typed primitive leaves
(Symbol, String, I64, F64, Bool). Five composites
(Bind, Bundle, Permute, Thermometer, Blend). Plus
Atom(Arc<HolonAST>) — the wrap, narrowed.
Hash + Eq + PartialEq derive cleanly (manual impls because f64
fields use to_bits per the standard NaN-Hash dance, but the
shape is mechanical). AtomTypeRegistry retires entirely; it has
nothing to dispatch on. The wat-lru shim’s “primitives only” panic
goes away. LocalCache<HolonAST, V> works directly. Everything
that was waiting on the algebra to close unblocks at once.
Atom keeps its job (Chapter 54 preserved)
Section titled “Atom keeps its job (Chapter 54 preserved)”Chapter 54 made a distinction we needed to keep: (Atom (quote some-program)) produces an opaque-identity vector — single
SHA-256 of canonical bytes, no decomposition — that is
SEMANTICALLY DISTINCT from the program’s structural vector. One
treats the program as an atomic identity for cosine; the other
exposes its sub-parts via unbind. Collapsing them would lose a
real algebraic operation.
So Atom survives — narrowed from Arc<dyn Any> to
Arc<HolonAST>. The wrap’s job is opaque-identity-around-a-holon,
not “container for arbitrary Rust.” And the wrap is repeatable:
Atom(Atom(x)) ≠ Atom(x) ≠ x, mirroring Lisp’s '(quote x) ≠
'x. Quote-towers preserved as a real algebraic operation.
Two stories the consumer chooses
Section titled “Two stories the consumer chooses”Slice 2 forced a second recognition. The user, asking whether
(Atom (lambda (x) (* x x))) is still valid:
the atom is meant ‘to hold’ forms - not eval them - someone else can eval them
we can just (quote :the-next-form) all the way down
we tell both stories?… the users can choose ‘do i want next form?’ or ‘do i want the value?’
Two stories. One substrate.
Story 1 — coordinate. `(:wat::holon::Atom (:wat::core::quote