roadmap: stateful-islands milestone — bounded mutation for streaming workloads
P2 entry: Stateful a b first-class type + !Mut effect + mut syntactic block, with uniqueness inference at the boundary. Motivated by the 2026-05-15 myc-vs-AILang analysis showing AILang's pure-only model cannot match the stateful-closure-plus-pipe idiom for online / streaming workloads (rolling indicators, IIR filters, online stats). The signature-as-contract thesis is *better* served by explicit Stateful + !Mut annotations than by myc's implicit closure-mutation: time-identity becomes visible in signatures without body inspection. Decision 10's no-shared-mutable-refs forbids aliased mutation; it does not forbid uniqueness-bounded mutation, which is the Lean 4 / Roc / Haskell-ST / Koka layered-design pattern. Ten blockers identified, from effect-handler infrastructure (the first non-IO/non-Diverge effect) through uniqueness inference for var captures, mutable-array primitive, runST-equivalent escape discharge, Form-A surface design, codegen for mutable struct-field writes, escape analysis for var/ref values, Decision-10 amendment vs. Decision 12, streaming bench corpus, and LLM-utility fieldtest.
This commit is contained in:
+111
@@ -265,6 +265,117 @@ clean. Pick the next milestone from P2.)_
|
||||
exercising the LLM-natural Show-body shape.
|
||||
- context: per-iter journal 2026-05-13-iter-str-concat.md.
|
||||
|
||||
- [ ] **\[milestone\]** Stateful islands — bounded mutation for
|
||||
streaming workloads (`Stateful a b` + `!Mut` effect + `mut`
|
||||
syntactic block). Adds a sealed mutable-state layer on top of
|
||||
the pure core: a `Stateful a b` first-class type whose interior
|
||||
is mutable, whose exterior is a typed callable with `!Mut` in
|
||||
its effect set, and whose state non-aliasing is enforced by
|
||||
uniqueness inference at the block boundary. Targets the
|
||||
online / streaming workload class — rolling indicators, IIR
|
||||
filters, online aggregates, sensor fusion, online learning —
|
||||
whose mathematics is "new sample + old state → new state +
|
||||
output" per step, and which today's pure-functional state-
|
||||
threading makes ergonomically expensive at scale (multi-record
|
||||
explicit threading for the canonical sliding-window SMA, no
|
||||
zero-allocation pipe combinator, growing tuple-state types as
|
||||
pipelines lengthen).
|
||||
|
||||
**Motivation.** AILang's signature-as-contract thesis is *better*
|
||||
served by an explicit `Stateful a b` + `!Mut` annotation than by
|
||||
the implicit-closure-mutation idiom of myc / Lua / JS factory
|
||||
patterns: the signature tells the truth about time-identity
|
||||
without the body needing to be read — exactly the LLM-author
|
||||
correctness affordance AILang exists to deliver, extended to a
|
||||
workload class it does not yet serve. Decision 10's constraint #3
|
||||
forbids *shared* mutable refs (DESIGN.md:1082); it does not
|
||||
forbid uniqueness-bounded mutation. Lean 4 (`ST`), Roc (`Task`),
|
||||
Haskell (`ST`/`IO`), and Koka (effects) all use a layered design
|
||||
of this shape to host exactly this workload. AILang's existing
|
||||
`own` / `borrow` mode machinery plus its effect-slot architecture
|
||||
are the foundation; this milestone supplies the layer that sits
|
||||
on top.
|
||||
|
||||
**Scope (subject to brainstorm refinement).**
|
||||
- `Stateful a b` as a first-class type — a sealed callable with a
|
||||
hidden mutable env, externally a typed callable whose effect
|
||||
set includes `!Mut`.
|
||||
- `!Mut` effect, the first non-IO / non-Diverge effect; forces
|
||||
the effect-handler infrastructure forward.
|
||||
- `mut` block as the syntactic boundary in Form A — outside,
|
||||
AILang's pure self; inside, `var` / `assign` / mutable arrays /
|
||||
while-loops legal.
|
||||
- `var x = expr` + `assign x expr` AST nodes, legal only inside
|
||||
`mut`.
|
||||
- Mutable array primitive (`MutArray a`, O(1) index/update under
|
||||
uniqueness) — co-developed because the ring-buffer use case
|
||||
that motivates the whole effort has no carrier today.
|
||||
- `pipe : Stateful a b → Stateful b c → Stateful a c` as a
|
||||
built-in combinator with zero-allocation lowering — composition
|
||||
is fusion at codegen, not closure-pair layering at runtime.
|
||||
- Decision 12 (or amendment to Decision 10) that names
|
||||
uniqueness-bounded mutation as the legitimate exception to
|
||||
"no shared mutable refs", and the pure / mutable-island layering
|
||||
as the architectural shape.
|
||||
|
||||
**Blockers (hard prerequisites + open design questions).**
|
||||
- *Effect handlers absent.* DESIGN.md:2663 — "No effect
|
||||
handlers — only the built-in IO and Diverge ops." `!Mut` is the
|
||||
first non-trivial effect and forces handler infrastructure to
|
||||
ship. May warrant lifting out as its own prerequisite milestone;
|
||||
brainstorm decides.
|
||||
- *Uniqueness inference through `var` captures.* Current
|
||||
inference operates over the immutable RC graph; mutable
|
||||
bindings captured by closures need a more powerful pass. Lean 4
|
||||
has a known algorithm; AILang does not implement it.
|
||||
- *No mutable-array primitive.* No `Array a`, no slab container
|
||||
of any kind in the language today. Separate spec needed inside
|
||||
this milestone (representation, `own`-only or `borrow`-able,
|
||||
bounds-checking discipline).
|
||||
- *`runST`-equivalent escape discharge.* Producing a `Stateful`
|
||||
that legitimately escapes its `mut` block while proving the
|
||||
inner state doesn't leak. Haskell's rank-2 trick
|
||||
(`runST :: (forall s. ST s a) -> a`) is unavailable —
|
||||
DESIGN.md:1930 confirms higher-rank polymorphism is not
|
||||
supported. Need an alternative — likely sealed-by-construction
|
||||
at the factory boundary, or an effect-mode tag that gates
|
||||
escape.
|
||||
- *Form A surface design.* Decision 1 forbids macros (source =
|
||||
data, not text), so `mut` / `var` / `assign` are genuine AST
|
||||
nodes with round-trip-invariant coverage. Surface needs LLM-
|
||||
utility validation (does the author reach for `var` / `mut`
|
||||
unprompted?) before implementation.
|
||||
- *Codegen for in-place struct-field writes.* `Term::ReuseAs`
|
||||
today lowers ADT in-place rewrite; no direct mutable struct-
|
||||
field-write path exists. `crates/ailang-codegen/src/escape.rs`
|
||||
plus the lowering passes need extension.
|
||||
- *Boundary escape analysis.* "Interior state doesn't leak" is an
|
||||
escape analysis specifically over `var` / `ref` values; the
|
||||
existing pass covers allocations, not mutable cells.
|
||||
- *Decision-10 status.* Whether to amend Decision 10 inline or
|
||||
add a Decision 12 that names the mutable-island layer alongside
|
||||
the pure layer. The latter is probably cleaner — Decision 10
|
||||
stays load-bearing for the pure layer, Decision 12 names the
|
||||
extension and its discipline.
|
||||
- *Streaming bench corpus.* Current corpus (list_sum, tree_walk,
|
||||
closure_chain, hof_pipeline) is all pure. Streaming-specific
|
||||
benches (SMA pipeline, IIR filter, online stats) plus an
|
||||
external baseline (myc, hand-C, Python/NumPy) need to exist to
|
||||
validate that the layered design hits the zero-alloc
|
||||
performance target that myc demonstrates.
|
||||
- *LLM-utility test.* DESIGN.md §"Feature-acceptance criterion"
|
||||
is the gate: the surface must produce code an LLM author
|
||||
naturally writes. Fieldtest after spec, before any code
|
||||
commits.
|
||||
|
||||
- context: 2026-05-15 chat on the `~/sma_factory.myc` analysis —
|
||||
myc's stateful-closure-plus-pipe idiom delivers a streaming
|
||||
workload pattern (3-line SMA factory, 2-line pipeline, zero
|
||||
runtime allocation per tick) that AILang's pure-only model
|
||||
cannot match without this layered extension. Pending brainstorm
|
||||
will produce `docs/specs/<date>-stateful-islands.md` and decide
|
||||
the effect-handler-prerequisite question.
|
||||
|
||||
## P3 — Ideas
|
||||
|
||||
- [x] **\[todo\]** `compare_primitives_smoke.ail` counterpart.
|
||||
|
||||
Reference in New Issue
Block a user