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:
parent
f8bf384b93
commit
297d92fbb8
4 changed files with 46 additions and 42 deletions
|
|
@ -219,11 +219,8 @@
|
|||
~@(map (fn [g] (impl (first g) (rest g))) (group-by-head body)))))
|
||||
|
||||
;; --- laziness --------------------------------------------------------------
|
||||
;; lazy-seq defers its body: make-lazy-seq holds a thunk that, when forced,
|
||||
;; realizes the body to cells. lazy-cat wraps each coll in a lazy-seq and concats
|
||||
;; (concat is itself lazy, so no outer wrapping needed).
|
||||
(defmacro lazy-seq [& body]
|
||||
`(make-lazy-seq (fn* [] (coll->cells (do ~@body)))))
|
||||
|
||||
(defmacro lazy-cat [& colls]
|
||||
`(concat ~@(map (fn [c] `(lazy-seq ~c)) colls)))
|
||||
;; lazy-seq / lazy-cat moved to the 00-syntax tier: the seq/coll tiers (10-seq,
|
||||
;; 20-coll) use lazy-seq, and in compile mode a tier's forms are compiled as it
|
||||
;; loads — so the macro must be registered BEFORE those tiers, else (lazy-seq …)
|
||||
;; compiles as a call to the macro-as-function and leaks its expansion at runtime
|
||||
;; (jolt-r81). They only need seed fns (make-lazy-seq/coll->cells/concat).
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue