From 67449f5b0cfe52bfb6bab9954a36daa599a3fdd5 Mon Sep 17 00:00:00 2001 From: giles Date: Mon, 11 May 2026 21:19:01 +0000 Subject: [PATCH] kernel: append + reverse + 11 tests [nothing] Variadic append concatenates lists; reverse is unary. 307 tests total. --- lib/kernel/runtime.sx | 46 +++++++++++++++++++++++++++++++++++- lib/kernel/tests/standard.sx | 27 +++++++++++++++++++++ plans/kernel-on-sx.md | 1 + 3 files changed, 73 insertions(+), 1 deletion(-) diff --git a/lib/kernel/runtime.sx b/lib/kernel/runtime.sx index 06b531bc..755599b8 100644 --- a/lib/kernel/runtime.sx +++ b/lib/kernel/runtime.sx @@ -490,6 +490,48 @@ "pair?" (fn (v) (and (list? v) (> (length v) 0))))) +(define knl-append-step + (fn (xs ys) + (cond + ((or (nil? xs) (= (length xs) 0)) ys) + (:else (cons (first xs) (knl-append-step (rest xs) ys)))))) + +(define knl-all-lists? + (fn (xs) + (cond + ((or (nil? xs) (= (length xs) 0)) true) + ((list? (first xs)) (knl-all-lists? (rest xs))) + (:else false)))) + +(define knl-append-all + (fn (lists) + (cond + ((or (nil? lists) (= (length lists) 0)) (list)) + ((= (length lists) 1) (first lists)) + (:else + (knl-append-step (first lists) + (knl-append-all (rest lists))))))) + +(define kernel-append-applicative + (kernel-make-primitive-applicative + (fn (args) + (cond + ((knl-all-lists? args) (knl-append-all args)) + (:else (error "append: all arguments must be lists")))))) + +(define knl-reverse-step + (fn (xs acc) + (cond + ((or (nil? xs) (= (length xs) 0)) acc) + (:else (knl-reverse-step (rest xs) (cons (first xs) acc)))))) + +(define kernel-reverse-applicative + (knl-unary-app "reverse" + (fn (xs) + (cond + ((not (list? xs)) (error "reverse: argument must be a list")) + (:else (knl-reverse-step xs (list))))))) + (define kernel-not-applicative (knl-unary-app "not" (fn (v) (not v)))) (define kernel-eq?-applicative (knl-bin-app "eq?" (fn (a b) (= a b)))) @@ -816,7 +858,9 @@ (kernel-env-bind! env "map" kernel-map-applicative) (kernel-env-bind! env "filter" kernel-filter-applicative) (kernel-env-bind! env "reduce" kernel-reduce-applicative) - (kernel-env-bind! env "apply" kernel-apply-applicative) + (kernel-env-bind! env "apply" kernel-apply-applicative) + (kernel-env-bind! env "append" kernel-append-applicative) + (kernel-env-bind! env "reverse" kernel-reverse-applicative) (kernel-env-bind! env "not" kernel-not-applicative) (kernel-env-bind! env "make-encapsulation-type" kernel-make-encap-type-applicative) diff --git a/lib/kernel/tests/standard.sx b/lib/kernel/tests/standard.sx index 0569c77d..803dec0a 100644 --- a/lib/kernel/tests/standard.sx +++ b/lib/kernel/tests/standard.sx @@ -415,4 +415,31 @@ (ks-eval "(apply + 5)")) :raised) +;; ── append / reverse ──────────────────────────────────────────── +(ks-test "append: two lists" + (ks-eval "(append (list 1 2) (list 3 4))") (list 1 2 3 4)) +(ks-test "append: three lists" + (ks-eval "(append (list 1) (list 2) (list 3))") (list 1 2 3)) +(ks-test "append: empty list" + (ks-eval "(append)") (list)) +(ks-test "append: one list" + (ks-eval "(append (list 1 2 3))") (list 1 2 3)) +(ks-test "append: empty + nonempty" + (ks-eval "(append (list) (list 1 2))") (list 1 2)) +(ks-test "append: nonempty + empty" + (ks-eval "(append (list 1 2) (list))") (list 1 2)) +(ks-test "append: error on non-list" + (guard (e (true :raised)) + (ks-eval "(append (list 1) 5)")) + :raised) + +(ks-test "reverse: four elements" + (ks-eval "(reverse (list 1 2 3 4))") (list 4 3 2 1)) +(ks-test "reverse: empty" + (ks-eval "(reverse (list))") (list)) +(ks-test "reverse: single" + (ks-eval "(reverse (list 99))") (list 99)) +(ks-test "reverse: double reverse is identity" + (ks-eval "(reverse (reverse (list 1 2 3)))") (list 1 2 3)) + (define ks-tests-run! (fn () {:total (+ ks-test-pass ks-test-fail) :passed ks-test-pass :failed ks-test-fail :fails ks-test-fails})) diff --git a/plans/kernel-on-sx.md b/plans/kernel-on-sx.md index 67bc2cf7..ca204ca6 100644 --- a/plans/kernel-on-sx.md +++ b/plans/kernel-on-sx.md @@ -161,6 +161,7 @@ The motivation is that SX's host `make-env` family is registered only in HTTP/si ## Progress log +- 2026-05-11 — `append` (variadic) and `reverse`. Append concatenates any number of lists; empty `(append)` returns `()`. Reverse is unary. 11 new tests. chisel: nothing (textbook list ops). 307 tests total. - 2026-05-11 — `apply` combinator. `(apply F (list V1 V2 V3))` ≡ `(F V1 V2 V3)` but with the argument list constructed at runtime. Implementation: unwrap an applicative F to its underlying operative, then `kernel-combine` it with the values — skipping the auto-eval pass since args are already values. For a bare operative F, pass through directly. 7 new tests. chisel: shapes-reflective. The unwrap-then-combine pattern is universal across reflective Lisps and should be in the `combiner.sx` API alongside the existing wrap/unwrap pair: `refl-apply F ARGS DYN-ENV` is the third API entry needed for higher-order composition. 296 tests total. - 2026-05-11 — `map` / `filter` / `reduce` list combinators. Required adding `kernel-make-primitive-applicative-with-env` to `eval.sx`: standard primitive applicatives drop dyn-env, but combinators that re-enter the evaluator (calling user-supplied functions on each element) need it. The three combinators use `kernel-combine` directly with the captured dyn-env. 10 new tests covering map/filter/reduce on numbers, empty lists, closures, and list construction. chisel: shapes-reflective. The "primitive applicatives split into two flavours — env-blind and env-aware" finding goes into the proposed `lib/guest/reflective/combiner.sx` API. Every reflective Lisp must distinguish "I just need values" from "I need to re-enter evaluation" — the with-env constructor pair is universal. 289 tests total. - 2026-05-11 — Variadic `+ - * /` and chained `< > <=? >=?`. `(+ 1 2 3)` = 6, `(+)` = 0, `(+ 7)` = 7. `(- 10 1 2 3)` = 4 (left fold); single-arg `-` negates. `(* 1 2 3 4)` = 24, `(*)` = 1. Chained comparison: `(< 1 2 3)` ≡ `(< 1 2) ∧ (< 2 3)`. Implementation: `knl-fold-app` for n-ary fold with zero-arity identity and one-arity special-case; `knl-chain-cmp` for chained boolean. 19 new tests. chisel: nothing (mechanical extension of existing arithmetic primitives). 279 tests total.