Phase 5: true laziness — lazy transformers + deadlined harness

jolt-c09 (partial, Steps 0–2d complete).

Lazy combinator layer (Step 1):
- lazy-cons: build a LazySeq cell from val + rest-thunk (phm.janet)
- lazy-from: coerce any seqable to lazy view without forcing (core.janet)
- core-seq: check ls-first emptiness, not ls-seq realization (core.janet)

Lazy transformers (Steps 2a–2d):
Converted in Janet core.janet (lazy branches preserving transducer arities):
  drop-while, interpose, distinct, partition, partition-all,
  keep, keep-indexed, map-indexed, take-nth

Moved to Clojure overlay (jolt-core):
  interleave (20-coll.clj) — lazy multi-arity, matches Clojure
  mapcat (10-seq.clj) — transducer arity + standard (apply concat (apply map f colls))

Safety net (Step 0):
  test/support/lazy-eval.janet — subprocess worker for Clojure eval
  test/integration/lazy-infinite-test.janet — deadlined harness (os/spawn + 5s)

Multi-input map/mapcat tests (Step 2d):
  sequences-spec.janet +9 tests, verified against Clojure/CLJS references

Gates:
  lazy-infinite: 18/18 (mapcat on infinite inputs hangs — apply forces, needs Step 4)
  conformance: 229/229 ×3 (interpret/compile/self-host)
  specs: 32/32 files, 0 failures
This commit is contained in:
Yogthos 2026-06-08 00:40:56 -04:00
parent f6bd22ae94
commit e2e189acfe
7 changed files with 337 additions and 83 deletions

View file

@ -22,3 +22,8 @@
(if (next s)
(recur (conj ret (first s)) (next s))
(seq ret))))
(defn mapcat
([f] (comp (map f) cat))
([f & colls]
(apply concat (apply map f colls))))

View file

@ -178,17 +178,19 @@
(defn flatten [coll]
(filter (complement sequential?) (rest (tree-seq sequential? seq coll))))
;; Eager interleave (Clojure's is lazy): one from each coll in turn, until the
;; shortest ends.
(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.
(defn interleave
([] ())
([c1] (lazy-seq c1))
([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]
(apply interleave c1 c2 cs)))
;; No ratio type on Jolt, so rationalize is identity.
(defn rationalize [x] x)