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]
|
(defn comparator [pred]
|
||||||
(fn [a b] (cond (pred a b) -1 (pred b a) 1 :else 0)))
|
(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
|
(defn reductions
|
||||||
([f coll]
|
([f coll]
|
||||||
(let [s (seq coll)]
|
(lazy-seq
|
||||||
(if s
|
(let [s (seq coll)]
|
||||||
(reductions f (first s) (rest s))
|
(if s
|
||||||
(list (f)))))
|
(reductions f (first s) (rest s))
|
||||||
|
(list (f))))))
|
||||||
([f init coll]
|
([f init coll]
|
||||||
(loop [acc init xs (seq coll) out [init]]
|
(letfn [(step [acc s]
|
||||||
(if xs
|
(cons acc
|
||||||
(let [a (f acc (first xs))] (recur a (next xs) (conj out a)))
|
(lazy-seq
|
||||||
out))))
|
(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
|
;; Lazy pre-order DFS (matches Clojure). letfn-bound walk (not (fn walk …)) so it
|
||||||
;; Clojure semantics but triggers compile-mode issues in self-hosted compilation.
|
;; compiles cleanly in the overlay under :compile? — see jolt-r81.
|
||||||
;; 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)))
|
|
||||||
(defn tree-seq [branch? children root]
|
(defn tree-seq [branch? children root]
|
||||||
(let [walk (fn walk [acc node]
|
(letfn [(walk [node]
|
||||||
(let [acc (conj acc node)]
|
(lazy-seq
|
||||||
(if (branch? node)
|
(cons node
|
||||||
(reduce walk acc (children node))
|
(when (branch? node)
|
||||||
acc)))]
|
(mapcat walk (children node))))))]
|
||||||
(walk [] root)))
|
(walk root)))
|
||||||
|
|
||||||
;; Canonical flatten via tree-seq: the leaves (non-sequential nodes) in order.
|
;; Canonical flatten via tree-seq: the leaves (non-sequential nodes) in order.
|
||||||
;; Flattens lists too (sequential?), matching Clojure/CLJS.
|
;; Flattens lists too (sequential?), matching Clojure/CLJS.
|
||||||
|
|
@ -191,19 +189,29 @@
|
||||||
(defn xml-seq [root]
|
(defn xml-seq [root]
|
||||||
(tree-seq (complement string?) (comp seq :content) root))
|
(tree-seq (complement string?) (comp seq :content) root))
|
||||||
|
|
||||||
;; Eager interleave: round-robin one element from each coll until any exhausts.
|
;; Lazy interleave: round-robin one element from each coll until any exhausts.
|
||||||
;; A lazy version (canonical Clojure cons-recursion) hits the same compile-mode
|
;; letfn-bound recursion (not top-level self-call) so the lazy-seq body compiles
|
||||||
;; overlay bug as reductions/tree-seq — a self-recursive lazy-seq leaks its macro
|
;; cleanly in the overlay — see jolt-r81.
|
||||||
;; expansion under :compile? (see jolt-r81). Eager until that's fixed.
|
(defn interleave
|
||||||
(defn interleave [& colls]
|
([] ())
|
||||||
(if (empty? colls)
|
([c1] (lazy-seq c1))
|
||||||
(list)
|
([c1 c2]
|
||||||
(let [cs (mapv vec colls)
|
(letfn [(step [s1 s2]
|
||||||
n (apply min (map count cs))]
|
(lazy-seq
|
||||||
(loop [i 0 out []]
|
(let [s1 (seq s1) s2 (seq s2)]
|
||||||
(if (< i n)
|
(when (and s1 s2)
|
||||||
(recur (inc i) (reduce (fn [o c] (conj o (nth c i))) out cs))
|
(cons (first s1)
|
||||||
out)))))
|
(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.
|
;; No ratio type on Jolt, so rationalize is identity.
|
||||||
(defn rationalize [x] x)
|
(defn rationalize [x] x)
|
||||||
|
|
|
||||||
|
|
@ -47,8 +47,9 @@
|
||||||
["first filter even? drop range" "4" "(first (filter even? (drop 3 (range))))"]
|
["first filter even? drop range" "4" "(first (filter even? (drop 3 (range))))"]
|
||||||
["take 3 remove odd? range" "(quote (0 2 4))" "(take 3 (remove odd? (range)))"]
|
["take 3 remove odd? range" "(quote (0 2 4))" "(take 3 (remove odd? (range)))"]
|
||||||
["take 3 drop-while <5 range" "(quote (5 6 7))" "(take 3 (drop-while (fn [x] (< x 5)) (range)))"]
|
["take 3 drop-while <5 range" "(quote (5 6 7))" "(take 3 (drop-while (fn [x] (< x 5)) (range)))"]
|
||||||
# interleave stays eager in overlay (lazy-seq macro breaks compile mode).
|
["take 4 interleave range iterate" "(quote (0 10 1 11))" "(take 4 (interleave (range) (iterate inc 10)))"]
|
||||||
# ["take 4 interleave range iterate" "(quote (0 10 1 11))" "(take 4 (interleave (range) (iterate inc 10)))"]
|
["take 4 reductions + range" "(quote (0 1 3 6))" "(take 4 (reductions + (range)))"]
|
||||||
|
["take 3 tree-seq infinite" "(quote (0 0 0))" "(take 3 (tree-seq (fn [_] true) (fn [n] [n]) 0))"]
|
||||||
["take 3 partition 2 range" "(quote ((0 1) (2 3) (4 5)))" "(take 3 (partition 2 (range)))"]
|
["take 3 partition 2 range" "(quote ((0 1) (2 3) (4 5)))" "(take 3 (partition 2 (range)))"]
|
||||||
["take 3 partition-all 2 range" "(quote ((0 1) (2 3) (4 5)))" "(take 3 (partition-all 2 (range)))"]
|
["take 3 partition-all 2 range" "(quote ((0 1) (2 3) (4 5)))" "(take 3 (partition-all 2 (range)))"]
|
||||||
["take 3 map-indexed vector range" "(quote ([0 0] [1 1] [2 2]))" "(take 3 (map-indexed vector (range)))"]
|
["take 3 map-indexed vector range" "(quote ([0 0] [1 1] [2 2]))" "(take 3 (map-indexed vector (range)))"]
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue