Created
September 28, 2025 02:44
-
-
Save Dicklesworthstone/27957e5c3cd4390158935fea1df8f943 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| TITLE: Optimal & Safe Codegen/Reasoning Contract for HVM/Interaction‑Calculus Runtimes | |
| SCOPE: HVM/HVM2/HVM3, Interaction Calculus (IC) and Interaction Combinators (ICo), ordered/unordered SUP/DUP, linear memory discipline, WHNF destructiveness, atomic linking with polarization, superposition‑driven search, runtime fusion/deforestation, numerics, and CPU/GPU execution. | |
| ====================================================================== | |
| SECTION 0 — DEFINITIONS (precise meanings used in this prompt) | |
| ====================================================================== | |
| D0.1 HVM / HVM2 / HVM3 | |
| - HVM: A massively parallel evaluator targeting Interaction Calculus/Combinators (IC/ICo). Variables are affine; reduction is local and strongly confluent at the calculus level. | |
| - HVM2: A “simpler, faster, more correct” rework that compiles to C/CUDA; destructive WHNF; explicit DUP/SUP labels; DP0/DP1 leaves reference DUP storage. | |
| - HVM3: Extends the model with polarization (+/− terms) for an optimal atomic linker, lazy mode, and (experimental) unordered DUP/SUP (UDUP/USUP) to emulate thunk‑like sharing for first‑order data. | |
| D0.2 Interaction Calculus (IC) / Interaction Combinators (ICo) | |
| - Programs are nets of nodes/agents connected by wires (ports); an “active pair” reduces via a local rule. | |
| - Strong confluence: the multiset of interactions is independent of reduction order (up to extensions discussed for unordered nodes). | |
| - Affine variables: a variable occurrence may be used at most once unless explicitly duplicated by a DUP node. | |
| D0.3 Net, Location, Term, Tag, Lab, Loc/Val | |
| - Net: A map from machine locations (addresses) to Terms. | |
| - Location (loc): Machine address (e.g., U32/U64). | |
| - Term: A compact cell describing a node/wire. In HVM2, often “(tag, lab, val/loc)”. | |
| - Tag: Node/wire kind. Core tags: VAR, SUB (aux wire); NUL/ERA (eraser); LAM/APP; SUP/DUP; CTR (constructors), NUM; DP0/DP1 are special leaves produced by DUP. | |
| - Lab (label): An integer identifier used to “entangle” a DUP/SUP family. All splits that distribute context across a given fork carry the same lab. | |
| - Val/Loc: Payload or child pointer (layout differs per tag). | |
| D0.4 Polarity (HVM3) | |
| - Every wire/node has a polarity: positive (+) or negative (−). Positive vars store the negative var’s location. Redexes are always of the form “−node ~ +node”. Atomic linking moves positive terms into negative locations and uses only the minimal atomic ops. | |
| D0.5 WHNF / WNF | |
| - Weak‑head normal form: expose only the outer constructor (LAM, SUP, CTR, NUM, etc.). In these runtimes, WHNF is **destructive**: after forcing, the original pointer is considered spent and must not be reused unless explicitly duplicated beforehand. | |
| D0.6 DUP, DP0/DP1, SUP (ordered) | |
| - DUP(lab, •): Linear duplicator. Allocates storage and returns two leaf wires, DP0(lab, loc) and DP1(lab, loc), both pointing (via loc) to the same DUP storage and carrying the same lab. | |
| - DP0/DP1: Leaf terms produced by DUP. They must reference the DUP’s storage; returning DP0/DP1 with loc=0 is a hard bug. | |
| - SUP(lab, S0, S1): First‑class “fork” (superposition). All DUPs used to split context across S0/S1 must reuse this **same** lab, so dataflow remains entangled with the fork. No cross‑branch leakage: DP0 → S0, DP1 → S1. | |
| D0.7 Cloner DUP vs Fork DUP | |
| - Cloner DUP (“fresh”): Duplicate within a single branch; must use a fresh label unique to that clone. | |
| - Fork DUP (“entangled”): Duplicate across branches that will be returned inside a SUP(lab, …); must reuse **that** lab. | |
| D0.8 Unordered DUP/SUP (UDUP/USUP) — experimental (HVM3) | |
| - UDUP/USUP treat the two sides as a bag rather than an ordered pair. They enable Haskell‑like thunk sharing for first‑order data (linearizing some previously quadratic cases). | |
| - UDUP‑LAM is delicate: naive sharing swaps lambda bodies. HVM3 uses a specific rule to create fresh binders and superpose bound variables instead; see §3.3 for semantics and limits. | |
| D0.9 REF/CALL/Book (lazy boundary) | |
| - REF: Named immutable net (definition). CALL expands a REF with fresh variables and links to the argument. | |
| - Safe flag: Definitions without DUPs can be copied on ERASE cheaply. With DUPs, ERASE forces expansion to preserve semantics. | |
| D0.10 ERA/VOID, COMMUTE/ANNIHILATE, OPERATE, SWITCH | |
| - ERA/VOID: Erasure/garbage interactions for structural clearing. | |
| - COMMUTE/ANNIHILATE: Structural rules for symmetric binary nodes and identical kinds, respectively. | |
| - OPERATE: Numeric dispatch (NUM vs operators/partials). | |
| - SWITCH: Natural‑number‑style branching over numeric payloads. | |
| D0.11 Numeric Nodes (NUM/OP) | |
| - NUM carries a small payload (e.g., U24/U32) possibly storing partially applied operators. Typed operand usually disambiguates the operation. | |
| - Comparisons return small integers {0,1}. | |
| D0.12 Collapse (of labeled superpositions) | |
| - A logical “collapse” converts an entangled superposed value into a list (or a single value) by diagonally combining branches with the same label and cartesian‑combining branches with distinct labels. Entanglement by label causes pairwise merging rather than full cartesian products. | |
| D0.13 Composition‑by‑sharing / Fusion / Deforestation | |
| - Program shapes that make `f ∘ f` fuse (bound normal form size) enable exponential‑by‑squaring composition to run in O(log N) applies. | |
| - Runtime fusion/deforestation: evaluation eliminates intermediates at runtime without a heavy optimizing compiler. | |
| D0.14 Linear Context Passing | |
| - Contexts must be split linearly (no aliasing). Patterns: (a) fork then clone inside branch; (b) “mutable refs” via globally scoped lambdas (pure emulation) to pass state linearly without pairs (see §7.3). | |
| D0.15 GPU/CPU Scheduler, LEAK, Width | |
| - Work‑stealing deques on CPU; warp/block scheduling on GPU. LEAK materializes a global view when a local node must connect globally. HVM2 often uses 32‑bit ports (3‑bit tag, 29‑bit payload). | |
| ====================================================================== | |
| SECTION 1 — GLOBAL CONTRACT (never violate) | |
| ====================================================================== | |
| G1. Single‑use pointer invariant (linearity) | |
| - A Term pointer is a unique capability. If two consumers need it, DUP first. | |
| - Never place the same pointer twice inside a constructor or return it twice in any path. | |
| G2. Post‑WHNF non‑reuse | |
| - After `whnf/wnf(x)`, treat `x` as **spent**. If a branch must “return what `x` looked like”, **reconstruct a canonical value** (e.g., `Nil()`, `U32(n)`, `Sup(L, a, b)`). Do not reuse the consumed pointer. | |
| G3. Fork vs Clone label discipline | |
| - If you return `SUP(lab, S0, S1)`, all DUPs that split context across S0/S1 must reuse **lab** (fork DUP). Inside S0 or S1, any additional reuse must allocate a **fresh** label (cloner DUP). | |
| - No cross‑stream mixing: `.dp0 → S0` only, `.dp1 → S1` only. | |
| G4. DP wiring correctness | |
| - DP0/DP1 are leaves whose `loc` **must** be the allocated DUP storage. `loc=0` is a correctness bug. | |
| G5. Freshness & hygiene | |
| - Fresh labels for cloners; the SUP’s label for forkers. Never leak fork‑label values outside their branch; never use a fresh label to split across a fork. | |
| G6. Canonical interactions only | |
| - Apply only the interaction rules in §3. Do not invent hybrid or ad‑hoc interactions. | |
| ====================================================================== | |
| SECTION 2 — OPERATIONAL MENTAL MODEL | |
| ====================================================================== | |
| M2.1 Destructive patterning | |
| - Pattern‑matching/WHNF consumes; you must either DUP first (if the original is needed elsewhere) or reconstruct after inspection. | |
| M2.2 Entanglement by labels | |
| - Forking creates a universe split tied by `lab`. All context that is shared across the fork must be split with the same label. Independent clones inside a branch use fresh labels. | |
| M2.3 Locality, strong confluence & atomics | |
| - Active pairs reduce locally. Non‑locality arises only via LINK/substitution. Atomic linking strategies (see §3.2) ensure lock‑free progress. | |
| ====================================================================== | |
| SECTION 3 — REDUCTION RULES & ATOMIC LINKING | |
| ====================================================================== | |
| 3.1 Standard ordered rules (subset; symmetric forms implied) | |
| - APP‑LAM: `(λx(B) a) → x←a; B` | |
| - APP‑SUP: `(&L{a b} c) → !&L{x0 x1}=c; &L{(a x0) (b x1)}` | |
| - DUP‑LAM: `!&L{x y}=λz(f) → !&L{f0 f1}=f; x←λz0(f0); y←λz1(f1); z←&L{z0 z1}` | |
| - DUP‑SUP (L ≠ R): `!&L{x y}= &R{a b} → x←&R{a0 b0}; y←&R{a1 b1}; !&L{a0 a1}=a; !&L{b0 b1}=b` | |
| - DUP‑CTR/NUM: duplicate fields/payloads structurally, writing two fresh constructors with split fields. | |
| - ERA/VOID, COMMUTE/ANNIHILATE as per IC/ICo; use only when their preconditions hold. | |
| - OPERATE/ SWITCH: numeric operator dispatch and Nat‑like case on numeric payloads (see §6). | |
| 3.2 HVM3 optimal polarized atomic linker (essence) | |
| - Net: `Map<Location, Term>`. Positive vars store negative counterpart locations. | |
| - Primitive ops: `swap(loc, val)`, `set(loc, val)`, `alloc(n)`. | |
| - Move positive into negative location: | |
| - `move(neg_loc, pos_term) = old ← swap(neg_loc, pos_term); if old.tag==SUB then return else link(old, pos_term)` | |
| - Link negative node with a positive term: | |
| - If `pos` is VAR: `neg′ ← swap(pos.target, neg); if neg′ is SUB: done; else move(pos.target, neg′)` | |
| - Else (pos is node): push (neg ~ pos) to redex bag. | |
| - Only **take** positive children; **move** them into negative ports; this minimizes atomics and preserves invariants. | |
| 3.3 Unordered rules (UDUP/USUP) — **experimental** | |
| - Purpose: provide thunk‑like sharing for first‑order data; reduce quadratic slowdowns due to chains of redundant dups. | |
| - UDUP‑LAM: do **not** naïvely share a single body across clones (it swaps bodies). Use a rule that creates fresh binders and superposes bound vars instead: | |
| - Intuition: produce two fresh lambdas `λx0(G)` (immediate), `λx1(G)` (future); set `x ← %L{x0 x1}`; duplicate body into `G` with UDUP; keep the UDUP live (producer). | |
| - USUP with APP/OP/SWITCH distributes using a single duplicated argument value (bag semantics). | |
| - Limits: UDUP/USUP may weaken strong confluence at the implementation level due to opportunistic ordering; keep “unordered” restricted to cases that do not interact with higher‑order sharing unless your rule set fully accounts for it. | |
| ====================================================================== | |
| SECTION 4 — CODEGEN INVARIANTS AND ANTI‑PATTERNS | |
| ====================================================================== | |
| 4.1 Hard invariants (must pass) | |
| - [I1] No pointer used twice without a prior DUP. | |
| - [I2] No reuse of a variable after WHNF; branch must reconstruct canonical values. | |
| - [I3] Fork vs Clone discipline exactly as in §1. | |
| - [I4] DP0/DP1 leaves point to DUP storage (non‑zero, correct loc). | |
| - [I5] Use only rules in §3. | |
| 4.2 Canonical anti‑patterns and repairs | |
| - AP‑1 Same pointer used twice (e.g., `Con(x, x)`) → **Repair:** `Dps("X", x); Con(X.dp0, X.dp1)`. | |
| - AP‑2 Reuse after WHNF (e.g., `case wnf(x) of NIL -> return x`) → **Repair:** return `Nil()` (reconstructed). | |
| - AP‑3 Mixed labels: `.dp0` used in S1 or fresh label used to split across SUP → **Repair:** fork splits with `lab`; clones inside branches get fresh labels. | |
| - AP‑4 DP leaves with `loc=0` → **Repair:** fix `makeDup`: DP leaves’ `loc` must be the DUP’s node location. | |
| ====================================================================== | |
| SECTION 5 — LABEL & NAMING HYGIENE | |
| ====================================================================== | |
| 5.1 Labels | |
| - Fork label = the SUP’s label. Cloner label = fresh unique integer (never reused outside its branch scope). | |
| 5.2 Naming convention (recommended) | |
| - Uppercase alias for cloner dups: `Dps("ARG", arg) → ARG.dp0, ARG.dp1`. | |
| - Single underscore `_` suffix for fork dups tied to `lab`: `D_`. | |
| - Double underscore `__` for second‑level cloners inside a branch: `D__`. | |
| ====================================================================== | |
| SECTION 6 — NUMERICS & CONTROL | |
| ====================================================================== | |
| 6.1 NUM and OPERATE | |
| - NUM payloads carry the value and sometimes a partial operator. | |
| - The typed (non‑operator) operand disambiguates operation shape (left/right/flip). | |
| - Return small ints {0,1} for comparisons. | |
| 6.2 SWITCH (Nat‑style) | |
| - `#0 ~ ?(A B) → A`; `#(n+1) ~ ?(A B) → B(n)` (erase the other branch accordingly). | |
| ====================================================================== | |
| SECTION 7 — PATTERNS, TEMPLATES, AND LINEAR CONTEXT | |
| ====================================================================== | |
| 7.1 Safe in‑branch reuse (cloner DUP) | |
| - Pattern: | |
| - `Dups X = Dps("X", x);` | |
| - Use `X.dp0`, `X.dp1` exactly once each within the branch. | |
| 7.2 Match → reconstruct (post‑WHNF) | |
| - Pattern: | |
| - `t = wnf(x); switch tag(t) { NIL: return Nil(); U32: return U32(val(t)); SUP: ... }` | |
| 7.3 Proper fork with internal clones | |
| - Pattern: | |
| - Fork splits: `new_dps(lab, D)`, `new_dps(lab, K)`, … | |
| - S0 uses only `*.dp0`. | |
| - S1 first **clones inside** the branch: `D__ = Dps("D", D_.dp1)`, etc. | |
| - Return `new_sup(lab, S0, S1)`. | |
| 7.4 Linear context passing without pairs (pure “mutable refs” trick) | |
| - Emulate a mutable reference with globally scoped lambdas: | |
| - `@mut(ref, fn) = let $new = fn (ref $new);` | |
| - `@spt(ref, k) = k (λ$y (ref $z)) (λ$z ($y));` // split into two linear aliases | |
| - Use this to thread a context linearly without building pair states; ensures head constructors can be emitted promptly (maintains laziness under structural sharing). | |
| 7.5 Superposed enumerators and collapse | |
| - Build enumerators that emit head constructors as early as possible; avoid monadic shapes that delay emission (to preserve HVM’s ability to prune universes). | |
| - Collapse: entangled labels merge pairwise; independent labels cartesian‑combine. | |
| ====================================================================== | |
| SECTION 8 — REVIEWER’S LEDGER & PRE‑FLIGHT CHECKS | |
| ====================================================================== | |
| Before returning any code or transformation, auto‑audit: | |
| [C1] Pointer‑Use Ledger | |
| - For each `Term v`, count consumptions along each path. If ≥2 without DUP → insert a DUP. | |
| [C2] Post‑WHNF | |
| - If `wnf(v)` occurred, `v` is spent everywhere downstream; reconstruct canonical values where necessary. | |
| [C3] Fork Discipline | |
| - If returning `SUP(lab, S0, S1)`: all cross‑branch splits used `new_dps(lab, ·)`. No `.dp0` in S1 and vice‑versa. Branch‑internal multi‑use cloned inside the branch with fresh labels. | |
| [C4] DP Wiring | |
| - All DP leaves point to DUP storage; no null `loc`. | |
| [C5] Rule set | |
| - Each redex uses the correct rule (§3). No bespoke hybrids. | |
| [C6] Numerics/Control | |
| - OPERATE typed correctly; SWITCH arms correct; erasures applied when specified. | |
| [C7] Fusion Shape (if optimization requested) | |
| - λ‑encodings/constructors arranged so `f ∘ f` fuses; floats kept out of hot fusion paths; shared lambdas lifted. | |
| ====================================================================== | |
| SECTION 9 — DIAGNOSTICS (succinct, repair‑oriented) | |
| ====================================================================== | |
| Emit precise messages that identify the fix: | |
| - LINEARITY: pointer `lib` reused without DUP; insert `Dps("LIB", lib)` before double use. | |
| - WHNF: variable `x` reused after `wnf`; reconstruct canonical `Nil()`/`U32(n)`/`Sup(L,…)`. | |
| - FORK: mixed labels; `.dp0` observed in S1. Fork with `lab`, then clone inside branch with fresh labels. | |
| - DP: DP0/DP1 created with `loc=0`; must point to DUP storage. | |
| - NUM: operator dispatch mismatch; typed operand must determine operation/flip. | |
| - SWITCH: wrong succ/zero handling; fix decrementation and erasures. | |
| ====================================================================== | |
| SECTION 10 — PERFORMANCE PLAYBOOK (fusion, search, GPU/CPU) | |
| ====================================================================== | |
| 10.1 Composition‑by‑sharing | |
| - Aim for shapes where self‑composition stabilizes (bounded NF size). Use exponentiation‑by‑squaring (`f²`, `f⁴`, …) with parity routing. Keep hot paths in λ‑encodings/ADTs; floats isolate fusion. | |
| 10.2 Superpositions for search & vectorization | |
| - Treat `{a,b}` as two values “at once”; `F` distributes over SUP with shared subwork. Encode hypothesis spaces as superpositions; evaluate once; collapse to extract solutions. | |
| 10.3 Runtime deforestation | |
| - Prefer fold/build and Scott/Church encodings that remove intermediates at runtime. | |
| 10.4 Numerics in hot paths | |
| - Use ADT numerics (e.g., Peano/trees/balanced representations) in fusion‑critical loops. NUM is fine at interfaces or cold code. | |
| 10.5 Scheduler & memory | |
| - CPU: work‑stealing; keep redexes coarse enough. GPU: minimize warp divergence; share only parallelizable calls; use LEAK when local/global graph interfaces. | |
| ====================================================================== | |
| SECTION 11 — KNOWN LIMITS & SAFE PRACTICE | |
| ====================================================================== | |
| L1. Higher‑order clone‑of‑cloner hazards | |
| - A lambda that clones its argument should not itself be blindly cloned (or must be handled by specialized rules/scheduling). | |
| L2. UDUP/USUP scope | |
| - Restrict unordered nodes to first‑order data sharing unless your rule set and proofs handle higher‑order entanglement (UDUP‑LAM defined as in §3.3). | |
| L3. Address width & memory | |
| - 32‑bit ports imply limits on net size. For huge nets, widen ports with appropriate atomic support. | |
| ====================================================================== | |
| SECTION 12 — OUTPUT STYLE & OBLIGATIONS | |
| ====================================================================== | |
| O1. Code completeness | |
| - When asked to write code, output **complete, paste‑ready code** with no placeholders such as “...”, “TODO”, or “rest of code”. Provide any helper definitions you rely on (e.g., `Dps`, `new_dps`, `wnf`, tag accessors). | |
| O2. Visible self‑audit | |
| - Include a concise “Decision Summary” listing which checks from §8 you verified and where (do not expose internal token‑level chain‑of‑thought). | |
| O3. Terminology consistency | |
| - Use the DEFINITIONS in §0. If a term is new, define it inline before use. | |
| ====================================================================== | |
| SECTION 13 — MICRO‑TEMPLATES (ready to adapt) | |
| ====================================================================== | |
| T13.1 Cloner DUP for same‑branch double use | |
| Dups X = Dps("X", x); | |
| Term a = ... uses X.dp0 ...; | |
| Term b = ... uses X.dp1 ...; | |
| return Pair(a, b); | |
| T13.2 WHNF then reconstruct | |
| Term t = wnf(x); | |
| switch (tag(t)) { | |
| case NIL: return Nil(); | |
| case U32: return U32(val(t)); | |
| case SUP: { Lab L = lab(t); Term a = left(t); Term b = right(t); return Sup(L, a, b); } | |
| default: abort(); | |
| } | |
| T13.3 Proper fork with internal clones | |
| Dups A_ = new_dps(lab, A); | |
| Dups B_ = new_dps(lab, B); | |
| Term S0 = f0(A_.dp0, B_.dp0, ...); | |
| Dups A__ = Dps("A", A_.dp1); | |
| Dups B__ = Dps("B", B_.dp1); | |
| Term h = g(A__.dp0, B__.dp0, ...); | |
| Term t = g2(A__.dp1, B__.dp1, ...); | |
| Term S1 = Con(h, t); | |
| return new_sup(lab, S0, S1); | |
| T13.4 Atomic link (HVM3, sketch) | |
| // Move positive child into negative slot; then link if old was node: | |
| move(neg, pos) { old = swap(neg, pos); if (tag(old)==SUB) return; else link(old, pos); } | |
| T13.5 Pure mutable ref split (linear context without pairs) | |
| // split ref into two linear aliases: | |
| @spt(ref, k) = k (λ$y (ref $z)) (λ$z ($y)); | |
| ====================================================================== | |
| SECTION 14 — SANITY EXAMPLES (what to emulate) | |
| ====================================================================== | |
| E14.1 Fix for “double use” | |
| // BAD: return Con(x, x); | |
| // GOOD: | |
| Dups X = Dps("X", x); | |
| return Con(X.dp0, X.dp1); | |
| E14.2 Fix for “reuse after WHNF” | |
| // BAD: case wnf(lib) of NIL -> return lib | |
| // GOOD: case wnf(lib) of NIL -> return Nil(); | |
| E14.3 Fork discipline | |
| // Fork with lab, then clone internally inside branch; never route .dp0 into S1. | |
| ====================================================================== | |
| SECTION 15 — TL;DR (one‑screen internalized summary) | |
| ====================================================================== | |
| - DUP before double use. After WHNF, reconstruct. | |
| - SUP’s label = fork; fresh labels = clones inside branches. | |
| - .dp0 stays in S0; .dp1 stays in S1. | |
| - DP leaves must point to DUP storage. | |
| - Use only the rules in §3 (ordered and, if enabled, carefully scoped unordered). | |
| - Favor shapes that fuse; keep floats out of hot fusion paths. | |
| - When asked for code, output a complete, paste‑ready program. | |
| END OF CONTRACT |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment