core: Phase 5 Option A — lazy interleave/reductions/tree-seq via letfn
These three were the last eager transformers, blocked by jolt-r81: a self- recursive lazy-seq in the overlay leaks its macro expansion under :compile? when recursion goes through a top-level name or (fn name …) self-name. Rewriting the recursion as letfn-bound (the form partition-by/mapcat/dedupe already use, which compiles cleanly) sidesteps the bug. All three are now lazy in interpret, compile, and self-host — completing Option A for every transformer. interleave: canonical lazy cons-recursion (2-arity) + map/concat (n-arity). reductions: letfn step accumulator. tree-seq: letfn walk + lazy mapcat. Gate: conformance 246x3, lazy-infinite 40/40 (+interleave/reductions/tree-seq infinite cases), fixpoint, self-host, specs+unit green. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
3a42438b68
commit
c7e162add4
2 changed files with 49 additions and 40 deletions
|
|
@ -151,36 +151,34 @@
|
|||
(defn comparator [pred]
|
||||
(fn [a b] (cond (pred a b) -1 (pred b a) 1 :else 0)))
|
||||
|
||||
;; Eager (Jolt has no laziness yet): a vector of the running accumulators.
|
||||
;; 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.
|
||||
(defn reductions
|
||||
([f coll]
|
||||
(let [s (seq coll)]
|
||||
(if s
|
||||
(reductions f (first s) (rest s))
|
||||
(list (f)))))
|
||||
(lazy-seq
|
||||
(let [s (seq coll)]
|
||||
(if s
|
||||
(reductions f (first s) (rest s))
|
||||
(list (f))))))
|
||||
([f init coll]
|
||||
(loop [acc init xs (seq coll) out [init]]
|
||||
(if xs
|
||||
(let [a (f acc (first xs))] (recur a (next xs) (conj out a)))
|
||||
out))))
|
||||
(letfn [(step [acc s]
|
||||
(cons acc
|
||||
(lazy-seq
|
||||
(let [s (seq s)]
|
||||
(when s
|
||||
(step (f acc (first s)) (rest s)))))))]
|
||||
(step init coll))))
|
||||
|
||||
;; The lazy tree-seq (using lazy-seq/make-lazy-seq) correctly implements
|
||||
;; Clojure semantics but triggers compile-mode issues in self-hosted compilation.
|
||||
;; When compile mode is fixed, replace the eager version below with:
|
||||
;; (defn tree-seq [branch? children root]
|
||||
;; (let [walk (fn walk [node]
|
||||
;; (lazy-seq
|
||||
;; (cons node
|
||||
;; (when (branch? node)
|
||||
;; (mapcat walk (children node))))))]
|
||||
;; (walk root)))
|
||||
;; Lazy pre-order DFS (matches Clojure). letfn-bound walk (not (fn walk …)) so it
|
||||
;; compiles cleanly in the overlay under :compile? — see jolt-r81.
|
||||
(defn tree-seq [branch? children root]
|
||||
(let [walk (fn walk [acc node]
|
||||
(let [acc (conj acc node)]
|
||||
(if (branch? node)
|
||||
(reduce walk acc (children node))
|
||||
acc)))]
|
||||
(walk [] root)))
|
||||
(letfn [(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.
|
||||
;; Flattens lists too (sequential?), matching Clojure/CLJS.
|
||||
|
|
@ -191,19 +189,29 @@
|
|||
(defn xml-seq [root]
|
||||
(tree-seq (complement string?) (comp seq :content) root))
|
||||
|
||||
;; Eager interleave: round-robin one element from each coll until any exhausts.
|
||||
;; A lazy version (canonical Clojure cons-recursion) hits the same compile-mode
|
||||
;; overlay bug as reductions/tree-seq — a self-recursive lazy-seq leaks its macro
|
||||
;; expansion under :compile? (see jolt-r81). Eager until that's fixed.
|
||||
(defn interleave [& colls]
|
||||
(if (empty? colls)
|
||||
(list)
|
||||
(let [cs (mapv vec colls)
|
||||
n (apply min (map count cs))]
|
||||
(loop [i 0 out []]
|
||||
(if (< i n)
|
||||
(recur (inc i) (reduce (fn [o c] (conj o (nth c i))) out cs))
|
||||
out)))))
|
||||
;; 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)))
|
||||
([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)))))
|
||||
|
||||
;; No ratio type on Jolt, so rationalize is identity.
|
||||
(defn rationalize [x] x)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue