core: fix jolt-r81 at root — move lazy-seq/lazy-cat to the early syntax tier

Root cause: lazy-seq/lazy-cat were defined in 30-macros, which loads AFTER the
seq/coll tiers (10-seq, 20-coll) that use them. In compile mode a tier's forms
are compiled as the tier loads, so (lazy-seq …) in those tiers was compiled when
lazy-seq was not yet a registered macro — i.e. as a CALL to the macro-as-function,
which at runtime returns its own expansion `(make-lazy-seq (fn* [] …))` as data.
That leaked form then flowed into ops like `odd?` (partition-by) → type errors,
or silently produced wrong structure. Interpret/self-host masked it (expand at
call time); the eager fallbacks and the earlier letfn versions masked it by
falling back to the interpreter.

Fix: define lazy-seq/lazy-cat in 00-syntax (loaded first), exactly as when-let
already is for the same reason. They use only seed fns (make-lazy-seq/coll->cells/
concat) + map. With the macro registered early, the seq/coll tiers compile
(lazy-seq …) correctly.

With the root fixed, interleave/reductions/tree-seq drop their letfn workarounds
and use the canonical recursive Clojure forms (top-level / fn-self-name recursion
inside lazy-seq), verified leak-free in compile mode with strict probes.

Regression guards added: partition-by with odd? (the strict pred that exposed the
leak; the prior case used identity which masked it), reductions over an infinite
range, tree-seq summed through a strict filter — all ×3 modes.

Gate: conformance 249x3, lazy-infinite 40/40, fixpoint, self-host, specs+unit green.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
Yogthos 2026-06-08 17:47:52 -04:00
parent f8bf384b93
commit 297d92fbb8
4 changed files with 46 additions and 42 deletions

View file

@ -151,9 +151,7 @@
(defn comparator [pred]
(fn [a b] (cond (pred a b) -1 (pred b a) 1 :else 0)))
;; Lazy: the running accumulators, one at a time (matches Clojure). Recursion is
;; letfn-bound (NOT top-level self-call) so the lazy-seq body compiles cleanly in
;; the overlay — see jolt-r81.
;; Lazy: the running accumulators, one at a time (matches Clojure).
(defn reductions
([f coll]
(lazy-seq
@ -162,22 +160,19 @@
(reductions f (first s) (rest s))
(list (f))))))
([f init coll]
(letfn [(step [acc s]
(cons acc
(lazy-seq
(let [s (seq s)]
(when s
(step (f acc (first s)) (rest s)))))))]
(step init coll))))
(cons init
(lazy-seq
(when-let [s (seq coll)]
(reductions f (f init (first s)) (rest s)))))))
;; Lazy pre-order DFS (matches Clojure). letfn-bound walk (not (fn walk …)) so it
;; compiles cleanly in the overlay under :compile? — see jolt-r81.
;; Lazy pre-order DFS (matches Clojure): node, then its children's walks spliced
;; via the (now lazy) mapcat.
(defn tree-seq [branch? children root]
(letfn [(walk [node]
(lazy-seq
(cons node
(when (branch? node)
(mapcat walk (children node))))))]
(let [walk (fn walk [node]
(lazy-seq
(cons node
(when (branch? node)
(mapcat walk (children node))))))]
(walk root)))
;; Canonical flatten via tree-seq: the leaves (non-sequential nodes) in order.
@ -190,28 +185,22 @@
(tree-seq (complement string?) (comp seq :content) root))
;; Lazy interleave: round-robin one element from each coll until any exhausts.
;; letfn-bound recursion (not top-level self-call) so the lazy-seq body compiles
;; cleanly in the overlay — see jolt-r81.
(defn interleave
([] ())
([c1] (lazy-seq c1))
([c1 c2]
(letfn [(step [s1 s2]
(lazy-seq
(let [s1 (seq s1) s2 (seq s2)]
(when (and s1 s2)
(cons (first s1)
(cons (first s2)
(step (rest s1) (rest s2))))))))]
(step c1 c2)))
(lazy-seq
(let [s1 (seq c1) s2 (seq c2)]
(when (and s1 s2)
(cons (first s1)
(cons (first s2)
(interleave (rest s1) (rest s2))))))))
([c1 c2 & cs]
(letfn [(step [ss]
(lazy-seq
(let [ss (map seq ss)]
(when (every? identity ss)
(concat (map first ss)
(step (map rest ss)))))))]
(step (list* c1 c2 cs)))))
(lazy-seq
(let [ss (map seq (list* c1 c2 cs))]
(when (every? identity ss)
(concat (map first ss)
(apply interleave (map rest ss))))))))
;; No ratio type on Jolt, so rationalize is identity.
(defn rationalize [x] x)