From d1a491e53090d24eb7859194c27375cfdab23459 Mon Sep 17 00:00:00 2001 From: giles Date: Fri, 8 May 2026 23:00:39 +0000 Subject: [PATCH] =?UTF-8?q?apl:=20=E2=8D=8E=20execute=20=E2=80=94=20eval?= =?UTF-8?q?=20string=20as=20APL=20source=20(+8)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - apl-execute: reassemble char-vector ravel into single string, then apl-run; handles plain string, scalar, and char-vector - nested ⍎ ⍎ works; ⋄ separator threads through - pipeline 148/148 --- lib/apl/tests/pipeline.sx | 34 ++++++++++++++++++++++++++++++++++ lib/apl/transpile.sx | 9 +++++++++ plans/apl-on-sx.md | 3 ++- 3 files changed, 45 insertions(+), 1 deletion(-) diff --git a/lib/apl/tests/pipeline.sx b/lib/apl/tests/pipeline.sx index 24991bf7..3a8354cf 100644 --- a/lib/apl/tests/pipeline.sx +++ b/lib/apl/tests/pipeline.sx @@ -627,3 +627,37 @@ "⊆ partition: outer length matches partition count" (len (get (apl-run "1 0 1 0 1 ⊆ ⍳5") :ravel)) 3)) + +(begin + (apl-test + "⍎ execute: ⍎ '1 + 2' → 3" + (mkrv (apl-run "⍎ '1 + 2'")) + (list 3)) + (apl-test + "⍎ execute: ⍎ '+/⍳10' → 55" + (mkrv (apl-run "⍎ '+/⍳10'")) + (list 55)) + (apl-test + "⍎ execute: ⍎ '⌈/ 1 3 9 5 7' → 9" + (mkrv (apl-run "⍎ '⌈/ 1 3 9 5 7'")) + (list 9)) + (apl-test + "⍎ execute: ⍎ '⍳5' → 1..5" + (mkrv (apl-run "⍎ '⍳5'")) + (list 1 2 3 4 5)) + (apl-test + "⍎ execute: ⍎ '×/⍳5' → 120" + (mkrv (apl-run "⍎ '×/⍳5'")) + (list 120)) + (apl-test + "⍎ execute: round-trip ⍎ ⎕FMT 42 → 42" + (mkrv (apl-run "⍎ ⎕FMT 42")) + (list 42)) + (apl-test + "⍎ execute: nested ⍎ ⍎" + (mkrv (apl-run "⍎ '⍎ ''2 × 3'''")) + (list 6)) + (apl-test + "⍎ execute: with assignment side-effect" + (mkrv (apl-run "⍎ 'q ← 99 ⋄ q + 1'")) + (list 100))) diff --git a/lib/apl/transpile.sx b/lib/apl/transpile.sx index be7c989f..5207c646 100644 --- a/lib/apl/transpile.sx +++ b/lib/apl/transpile.sx @@ -48,6 +48,7 @@ ((= g "⎕←") apl-quad-print) ((= g "⍸") apl-where) ((= g "∪") apl-unique) + ((= g "⍎") apl-execute) (else (error "no monadic fn for glyph"))))) (define @@ -574,3 +575,11 @@ (define apl-run (fn (src) (apl-eval-ast (parse-apl src) {}))) (define apl-run-file (fn (path) (apl-run (file-read path)))) + +(define + apl-execute + (fn + (arr) + (let + ((src (cond ((string? arr) arr) ((scalar? arr) (disclose arr)) (else (reduce str "" (get arr :ravel)))))) + (apl-run src)))) diff --git a/plans/apl-on-sx.md b/plans/apl-on-sx.md index 01d9c48b..79ae1fac 100644 --- a/plans/apl-on-sx.md +++ b/plans/apl-on-sx.md @@ -255,7 +255,7 @@ still need work to run as-written. Phase 10 closes both. 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 +- [x] **`⍎` 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: @@ -288,6 +288,7 @@ data; format for string templating. _Newest first._ +- 2026-05-08: Phase 10 step 5 — `⍎` execute. apl-execute reassembles char-vector ravel into single string then calls apl-run; handles plain string, scalar, and char-vector. `⍎ '1 + 2' → 3`, `⍎ '+/⍳10' → 55`, round-trip `⍎ ⎕FMT 42 → 42`, nested `⍎ ⍎ '...'` works, with `⋄` separator (assignment + use). Wired into apl-monadic-fn. +8 tests; pipeline 148/148 - 2026-05-08: Phase 10 step 4 — `⊆` partition. apl-partition: walk M and V together via reduce, opening a new partition where M[i]>M[i-1] (initial prev=0), continuing where M[i]≤prev∧M[i]≠0, dropping cells where M[i]=0. Returns apl-vector of apl-vector parts. `1 1 0 1 1 ⊆ 'abcde' → ('ab' 'de')`, `1 0 0 1 1 ⊆ ⍳5 → ((1) (4 5))`, strict-increase `1 2` opens new, constant `2 2` continues. Wired into apl-dyadic-fn. +8 tests; pipeline 140/140 - 2026-05-08: Phase 10 step 3 — `⊥` decode / `⊤` encode. apl-decode (Horner reduce over indices, base[i]>0; scalar base broadcasts to digit length); apl-encode (right-to-left modulo+floor-div via reduce). Mixed-radix HMS works: `24 60 60 ⊥ 2 3 4 → 7384`, `24 60 60 ⊤ 7384 → 2 3 4`. Round-trips exact. Wired ⊥ ⊤ into apl-dyadic-fn. +11 tests; pipeline 132/132 - 2026-05-08: Phase 10 step 2 — `∪` unique / `∩` intersection. apl-unique (monadic, dedup keeping first-occurrence order via reduce+index-of), apl-union (dyadic, dedup'd A then B-elements-not-in-A), apl-intersect (dyadic, A elements that are also in B, preserves left order). Wired ∪ into both apl-monadic-fn and apl-dyadic-fn cond chains; ∩ into apl-dyadic-fn. +12 tests; pipeline 121/121