apl: train/fork notation (f g h) and (g h) (+6 tests, 496/496)
Some checks failed
Test, Build, and Deploy / test-build-deploy (push) Failing after 57s

Parser: when a parenthesised subexpression contains only function
segments (>= 2), collect-segments-loop now emits a :train AST node
instead of treating it as a value-producing expression.

Resolver: apl-resolve-{monadic,dyadic} handle :train.
- monadic 2-train (atop):  (g h)⍵ = g (h ⍵)
- monadic 3-train (fork):  (f g h)⍵ = (f ⍵) g (h ⍵)
- dyadic 2-train:          ⍺(g h)⍵ = g (⍺ h ⍵)
- dyadic 3-train:          ⍺(f g h)⍵ = (⍺ f ⍵) g (⍺ h ⍵)

apl-run "(+/÷≢) 1 2 3 4 5"  → 3   (mean)
apl-run "(- ⌊) 5"           → -5  (atop)
apl-run "2 (+ × -) 5"       → -21 (dyadic fork)
apl-run "(⌈/-⌊/) 3 1 4 …"   → 8   (range)
This commit is contained in:
2026-05-07 19:02:17 +00:00
parent a677585639
commit b661318a45
4 changed files with 85 additions and 6 deletions

View File

@@ -169,7 +169,7 @@ programs run from source, and starts pushing on performance.
one-liners (e.g. primes' inline `⍵←⍳⍵`) need parser features
(compress-as-fn, inline assign) we haven't built yet — multi-stmt forms
used instead. Slurp/read-file primitive missing in OCaml SX runtime.)_
- [ ] **Train/fork notation**`(f g h) ⍵ ↔ (f ⍵) g (h ⍵)` (3-train);
- [x] **Train/fork notation**`(f g h) ⍵ ↔ (f ⍵) g (h ⍵)` (3-train);
`(g h) ⍵ ↔ g (h ⍵)` (2-train atop). Parser: detect when a parenthesised
subexpression is all functions and emit `(:train fns)`; resolver: build the
derived function; tests for mean-via-train (`+/÷≢`).
@@ -191,6 +191,7 @@ data; format for string templating.
_Newest first._
- 2026-05-07: Phase 8 step 5 — train/fork notation. Parser :lparen detects all-fn inner segments → emits :train AST; resolver covers 2-atop & 3-fork for both monadic and dyadic. `(+/÷≢) 1..5 → 3` (mean), `(- ⌊) 5 → -5` (atop), `2(+×-)5 → -21` (dyadic fork), `(⌈/-⌊/) → 8` (range); +6 tests; 496/496
- 2026-05-07: Phase 8 step 4 — programs-e2e.sx runs classic-algorithm shapes through full pipeline (factorial via ∇, triangulars, sum-of-squares, divisor-counts, prime-mask, named-fn composition, dyadic max-of-two, Newton step); also added ⌿ + ⍀ to glyph sets (were silently skipped); +15 tests; 490/490
- 2026-05-07: Phase 8 step 3 — multi-axis bracket A[I;J] / A[I;] / A[;J] via :bracket AST + apl-bracket-multi runtime; split-bracket-content scans :semi at depth 0; apl-cartesian builds index combinations; nil axis = "all"; scalar axis collapses; +8 tests; 475/475
- 2026-05-07: Phase 8 step 2 — named function defs end-to-end via parser pre-scan; apl-known-fn-names + apl-collect-fn-bindings detect `name ← {...}` patterns; collect-segments-loop emits :fn-name for known names; resolver looks up env for :fn-name; supports recursion (∇ in named dfn); +7 tests including fact via ∇; 467/467