; APL idiom corpus — classic Roger Hui / Phil Last idioms expressed ; through our runtime primitives. Each test names the APL one-liner ; and verifies the equivalent runtime call. (define mkrv (fn (arr) (get arr :ravel))) (define mksh (fn (arr) (get arr :shape))) ; ---------- reductions ---------- (apl-test "+/⍵ — sum" (mkrv (apl-reduce apl-add (make-array (list 5) (list 1 2 3 4 5)))) (list 15)) (apl-test "(+/⍵)÷⍴⍵ — mean" (mkrv (apl-div (apl-reduce apl-add (make-array (list 5) (list 1 2 3 4 5))) (apl-scalar 5))) (list 3)) (apl-test "⌈/⍵ — max" (mkrv (apl-reduce apl-max (make-array (list 6) (list 3 1 4 1 5 9)))) (list 9)) (apl-test "⌊/⍵ — min" (mkrv (apl-reduce apl-min (make-array (list 6) (list 3 1 4 1 5 9)))) (list 1)) (apl-test "(⌈/⍵)-⌊/⍵ — range" (mkrv (apl-sub (apl-reduce apl-max (make-array (list 6) (list 3 1 4 1 5 9))) (apl-reduce apl-min (make-array (list 6) (list 3 1 4 1 5 9))))) (list 8)) (apl-test "×/⍵ — product" (mkrv (apl-reduce apl-mul (make-array (list 4) (list 1 2 3 4)))) (list 24)) (apl-test "+\\⍵ — running sum" (mkrv (apl-scan apl-add (make-array (list 5) (list 1 2 3 4 5)))) (list 1 3 6 10 15)) ; ---------- sort / order ---------- (apl-test "⍵[⍋⍵] — sort ascending" (mkrv (apl-quicksort (make-array (list 5) (list 3 1 4 1 5)))) (list 1 1 3 4 5)) (apl-test "⌽⍵ — reverse" (mkrv (apl-reverse (make-array (list 5) (list 1 2 3 4 5)))) (list 5 4 3 2 1)) (apl-test "⊃⌽⍵ — last element" (mkrv (apl-disclose (apl-reverse (make-array (list 4) (list 10 20 30 40))))) (list 40)) (apl-test "1↑⍵ — first element" (mkrv (apl-take (apl-scalar 1) (make-array (list 4) (list 10 20 30 40)))) (list 10)) (apl-test "1↓⍵ — drop first" (mkrv (apl-drop (apl-scalar 1) (make-array (list 4) (list 10 20 30 40)))) (list 20 30 40)) (apl-test "¯1↓⍵ — drop last" (mkrv (apl-drop (apl-scalar -1) (make-array (list 4) (list 10 20 30 40)))) (list 10 20 30)) ; ---------- counts / membership ---------- (apl-test "≢⍵ — tally" (mkrv (apl-tally (make-array (list 7) (list 9 8 7 6 5 4 3)))) (list 7)) (apl-test "+/⍵=v — count occurrences of v" (mkrv (apl-reduce apl-add (apl-eq (make-array (list 7) (list 1 2 3 2 1 3 2)) (apl-scalar 2)))) (list 3)) (apl-test "0=N|M — divisibility test" (mkrv (apl-eq (apl-scalar 0) (apl-mod (apl-scalar 3) (apl-scalar 12)))) (list 1)) ; ---------- shape constructors ---------- (apl-test "N⍴1 — vector of N ones" (mkrv (apl-reshape (apl-scalar 5) (apl-scalar 1))) (list 1 1 1 1 1)) (apl-test "(N N)⍴0 — N×N zero matrix" (mkrv (apl-reshape (make-array (list 2) (list 3 3)) (apl-scalar 0))) (list 0 0 0 0 0 0 0 0 0)) (apl-test "⍳∘.=⍳ — N×N identity matrix" (mkrv (apl-outer apl-eq (apl-iota (apl-scalar 3)) (apl-iota (apl-scalar 3)))) (list 1 0 0 0 1 0 0 0 1)) (apl-test "⍳∘.×⍳ — multiplication table" (mkrv (apl-outer apl-mul (apl-iota (apl-scalar 3)) (apl-iota (apl-scalar 3)))) (list 1 2 3 2 4 6 3 6 9)) ; ---------- numerical idioms ---------- (apl-test "+\\⍳N — triangular numbers" (mkrv (apl-scan apl-add (apl-iota (apl-scalar 5)))) (list 1 3 6 10 15)) (apl-test "+/⍳N=N×(N+1)÷2 — sum of 1..N" (mkrv (apl-reduce apl-add (apl-iota (apl-scalar 10)))) (list 55)) (apl-test "×/⍳N — factorial via iota" (mkrv (apl-reduce apl-mul (apl-iota (apl-scalar 5)))) (list 120)) (apl-test "2|⍵ — parity (1=odd)" (mkrv (apl-mod (apl-scalar 2) (make-array (list 5) (list 1 2 3 4 5)))) (list 1 0 1 0 1)) (apl-test "+/2|⍵ — count odd" (mkrv (apl-reduce apl-add (apl-mod (apl-scalar 2) (make-array (list 5) (list 1 2 3 4 5))))) (list 3)) ; ---------- boolean idioms ---------- (apl-test "∧/⍵ — all-true" (mkrv (apl-reduce apl-and (make-array (list 4) (list 1 1 1 1)))) (list 1)) (apl-test "∧/⍵ — all-true with zero is false" (mkrv (apl-reduce apl-and (make-array (list 4) (list 1 1 0 1)))) (list 0)) (apl-test "∨/⍵ — any-true" (mkrv (apl-reduce apl-or (make-array (list 4) (list 0 0 1 0)))) (list 1)) (apl-test "∨/⍵ — any-true all zero is false" (mkrv (apl-reduce apl-or (make-array (list 4) (list 0 0 0 0)))) (list 0)) ; ---------- selection / scaling ---------- (apl-test "⍵×⍵ — square each" (mkrv (apl-mul (make-array (list 4) (list 1 2 3 4)) (make-array (list 4) (list 1 2 3 4)))) (list 1 4 9 16)) (apl-test "+/⍵×⍵ — sum of squares" (mkrv (apl-reduce apl-add (apl-mul (make-array (list 4) (list 1 2 3 4)) (make-array (list 4) (list 1 2 3 4))))) (list 30)) (apl-test "⍵-(+/⍵)÷⍴⍵ — mean-centered" (mkrv (apl-sub (make-array (list 5) (list 2 4 6 8 10)) (apl-div (apl-reduce apl-add (make-array (list 5) (list 2 4 6 8 10))) (apl-scalar 5)))) (list -4 -2 0 2 4)) ; ---------- shape / structure ---------- (apl-test ",⍵ — ravel" (mkrv (apl-ravel (make-array (list 2 3) (list 1 2 3 4 5 6)))) (list 1 2 3 4 5 6)) (apl-test "⍴⍴⍵ — rank" (mkrv (apl-shape (apl-shape (make-array (list 2 3) (list 1 2 3 4 5 6))))) (list 2)) (apl-test "src: +/⍳N → triangular(N)" (mkrv (apl-run "+/⍳100")) (list 5050)) (apl-test "src: ×/⍳N → N!" (mkrv (apl-run "×/⍳6")) (list 720)) (apl-test "src: ⌈/V — max" (mkrv (apl-run "⌈/3 1 4 1 5 9 2 6")) (list 9)) (apl-test "src: ⌊/V — min" (mkrv (apl-run "⌊/3 1 4 1 5 9 2 6")) (list 1)) (apl-test "src: range = (⌈/V) - ⌊/V" (mkrv (apl-run "(⌈/3 1 4 1 5 9 2 6) - ⌊/3 1 4 1 5 9 2 6")) (list 8)) (apl-test "src: +\\V — running sum" (mkrv (apl-run "+\\1 2 3 4 5")) (list 1 3 6 10 15)) (apl-test "src: ×\\V — running product" (mkrv (apl-run "×\\1 2 3 4 5")) (list 1 2 6 24 120)) (apl-test "src: V × V — squares" (mkrv (apl-run "(⍳5) × ⍳5")) (list 1 4 9 16 25)) (apl-test "src: +/V × V — sum of squares" (mkrv (apl-run "+/(⍳5) × ⍳5")) (list 55)) (apl-test "src: ∧/V — all-true" (mkrv (apl-run "∧/1 1 1 1")) (list 1)) (apl-test "src: ∨/V — any-true" (mkrv (apl-run "∨/0 0 1 0")) (list 1)) (apl-test "src: 0 = N|M — divides" (mkrv (apl-run "0 = 3 | 12")) (list 1)) (apl-test "src: 2 | V — parity" (mkrv (apl-run "2 | 1 2 3 4 5 6")) (list 1 0 1 0 1 0)) (apl-test "src: +/2|V — count odd" (mkrv (apl-run "+/2 | 1 2 3 4 5 6")) (list 3)) (apl-test "src: ⍴ V" (mkrv (apl-run "⍴ 1 2 3 4 5")) (list 5)) (apl-test "src: ⍴⍴ M — rank" (mkrv (apl-run "⍴ ⍴ (2 3) ⍴ ⍳6")) (list 2)) (apl-test "src: N⍴1 — vector of ones" (mkrv (apl-run "5 ⍴ 1")) (list 1 1 1 1 1)) (apl-test "src: ⍳N ∘.= ⍳N — identity matrix" (mkrv (apl-run "(⍳3) ∘.= ⍳3")) (list 1 0 0 0 1 0 0 0 1)) (apl-test "src: ⍳N ∘.× ⍳N — multiplication table" (mkrv (apl-run "(⍳3) ∘.× ⍳3")) (list 1 2 3 2 4 6 3 6 9)) (apl-test "src: V +.× V — dot product" (mkrv (apl-run "1 2 3 +.× 4 5 6")) (list 32)) (apl-test "src: ∧.= V — vectors equal?" (mkrv (apl-run "1 2 3 ∧.= 1 2 3")) (list 1)) (apl-test "src: V[1] — first element" (mkrv (apl-run "(10 20 30 40)[1]")) (list 10)) (apl-test "src: 1↑V — first via take" (mkrv (apl-run "1 ↑ 10 20 30 40")) (list 10)) (apl-test "src: 1↓V — drop first" (mkrv (apl-run "1 ↓ 10 20 30 40")) (list 20 30 40)) (apl-test "src: ¯1↓V — drop last" (mkrv (apl-run "¯1 ↓ 10 20 30 40")) (list 10 20 30)) (apl-test "src: ⌽V — reverse" (mkrv (apl-run "⌽ 1 2 3 4 5")) (list 5 4 3 2 1)) (apl-test "src: ≢V — tally" (mkrv (apl-run "≢ 9 8 7 6 5 4 3 2 1")) (list 9)) (apl-test "src: ,M — ravel" (mkrv (apl-run ", (2 3) ⍴ ⍳6")) (list 1 2 3 4 5 6)) (apl-test "src: A=V — count occurrences" (mkrv (apl-run "+/2 = 1 2 3 2 1 3 2")) (list 3)) (apl-test "src: ⌈/(V × V) — max squared" (mkrv (apl-run "⌈/(1 2 3 4 5) × 1 2 3 4 5")) (list 25))