From fa43aa671174ab93785ef062eda90526fa1daf67 Mon Sep 17 00:00:00 2001 From: giles Date: Fri, 8 May 2026 07:27:22 +0000 Subject: [PATCH] =?UTF-8?q?plans:=20Phase=2010=20=E2=80=94=20runtime=20gap?= =?UTF-8?q?s=20(=E2=8D=B8=20=E2=88=AA=20=E2=88=A9=20=E2=8A=A5=20=E2=8A=A4?= =?UTF-8?q?=20=E2=8A=86=20=E2=8D=8E)=20+=20life/quicksort=20as-written?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- plans/apl-on-sx.md | 48 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/plans/apl-on-sx.md b/plans/apl-on-sx.md index 616d71ca..95afddef 100644 --- a/plans/apl-on-sx.md +++ b/plans/apl-on-sx.md @@ -227,6 +227,53 @@ Today they are documentation; we paraphrase the algorithms in in the runtime — parser sees them as functions but eval errors; next-phase work.)_ +### Phase 10 — fill runtime gaps + life/quicksort source files run + +Phase 9 left seven glyphs that the parser recognises but the runtime +cannot evaluate, and two source files (`life.apl`, `quicksort.apl`) that +still need work to run as-written. Phase 10 closes both. + +- [ ] **`⍸` where** — monadic `⍸ B` returns the indices of the truthy + cells (1-based per `⎕IO`). Dyadic `X ⍸ Y` is interval index (find + the largest `i` such that `X[i] ≤ Y`). Add `apl-where` + dyadic + `apl-interval-index`; wire both into `apl-monadic-fn` / `apl-dyadic-fn`. + Tests: `⍸ 0 1 0 1 1 → 2 4 5`, `⍸ ⍳5 = ¯1+⍳5 → empty`, + `2 4 6 ⍸ 5 → 2`. +- [ ] **`∪` unique / `∩` intersection** — monadic `∪ V` returns V with + duplicates removed (first-occurrence order); dyadic `A ∪ B` is + union; `A ∩ B` is intersection (members of A that are also in B). + Add `apl-unique`, `apl-union`, `apl-intersect`. Tests cover empty, + single, repeats, mixed numerics. +- [ ] **`⊥` decode / `⊤` encode** — `B ⊥ V` evaluates digits `V` in + base(s) `B` (Horner-style); `B ⊤ N` is the inverse, returning the + digits of `N` in base(s) `B`. Both broadcast `B` as scalar or + conformable vector. Add `apl-decode` and `apl-encode`. Tests: + `2 ⊥ 1 0 1 → 5`, `10 ⊥ 1 2 3 → 123`, `2 2 2 ⊤ 5 → 1 0 1`, + `24 60 60 ⊤ 7384 → 2 3 4`. +- [ ] **`⊆` partition** — dyadic `M ⊆ V` partitions `V` into vectors + driven by mask `M`: a new partition starts wherever `M[i] > M[i-1]`, + and 0 cells are dropped. Returns a vector of (boxed) partitions. + Add `apl-partition`. Tests: `1 1 0 1 1 ⊆ 'abcde' → ('ab' 'de')`, + `1 0 0 1 1 ⊆ ⍳5 → ((⊂ 1) (⊂ 4 5))`. +- [ ] **`⍎` execute** — monadic `⍎ S` evaluates `S` (a character + vector) as APL source in the *current* environment, returning the + result. Implement as `(fn (s) (apl-run s))` — env is the global + one; nested execute is fine. Wire into `apl-monadic-fn`. Tests: + `⍎ '1 + 2' → 3`, `⍎ '+/⍳10' → 55`. +- [ ] **`life.apl` runs as-written** — Conway's life one-liner uses + `⊃+/⌽¨ -1 0 1 ∘.,¯1 0 1` (each + outer-comma + disclose + reduce + over a list of rotations) and the rule expression. Probe what + fails when `apl-run-file "lib/apl/tests/programs/life.apl"` is + called on a 5×5 blinker grid; fix any remaining parser/runtime + gaps; assert blinker oscillates and block stays stable as full + end-to-end tests in `programs-e2e.sx`. +- [ ] **`quicksort.apl` runs as-written** — the classic Iverson dfn + `{1≥≢⍵:⍵ ⋄ (∇(⍵pivot)⌿⍵⊣pivot←⍵⌷⍨?≢⍵}` + exercises `⌷⍨` (squad-commute pivot pick), `⌿⍨` (first-axis-compress + commute), and `⊣` to bind a local without polluting the result. + Set the RNG seed for determinism and assert the sort against + `apl-grade-up`. + ## SX primitive baseline Use vectors for arrays; numeric tower + rationals for numbers; ADTs for tagged data; @@ -241,6 +288,7 @@ data; format for string templating. _Newest first._ +- 2026-05-08: Phase 10 added — fill runtime gaps (⍸ ∪ ∩ ⊥ ⊤ ⊆ ⍎) + life.apl and quicksort.apl as-written - 2026-05-07: Phase 9 step 6 — glyph audit. Wired ⍉ → apl-transpose/apl-transpose-dyadic, ⊢ → monadic+dyadic identity-right, ⊣ → identity-left, ⍕ → apl-quad-fmt. +6 tests; **Phase 9 complete, all unchecked items ticked**; pipeline 99/99 - 2026-05-07: Phase 9 step 5 — primes.apl runs as-written end-to-end. Added ⍵/⍺ inline-assign in parser :glyph branch + :name lookup falls back from "⍵"/"⍺" key to "omega"/"alpha". `apl-run "primes ← {(2=+⌿0=⍵∘.|⍵)/⍵←⍳⍵} ⋄ primes 50"` → 15 primes. +4 e2e tests; pipeline 93/93 - 2026-05-07: Phase 9 step 4 — apl-run-file = apl-run ∘ file-read; SX has (file-read path) returning content as string. primes/life/quicksort .apl files now load and parse end-to-end (return :dfn AST). +4 tests