From da2b065f46b4400f7be9dc01314da0a62459eb6a Mon Sep 17 00:00:00 2001 From: Yogthos Date: Mon, 8 Jun 2026 17:52:55 -0400 Subject: [PATCH] =?UTF-8?q?core:=20jolt-vzm=20=E2=80=94=20every=3F=20short?= =?UTF-8?q?-circuits=20lazily=20(boundary=20audit)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Audited all 43 realize-for-iteration call sites. Result: every? was the one transformer-style leak — it realized the whole coll before iterating, so (every? pos? (range)) hung instead of short-circuiting on the first false (Clojure short-circuits). Now walks lazy input cell-by-cell via realize-ls and stops at the first false; not-every? inherits the fix. Everything else is a legitimate realization boundary (reverse/sort/into/vec/set/ list/str-join/doall/apply/transient/to-array/hash-*/shuffle/rand-nth — must see all elements) or forces only finite/concrete input (drop-while's eager branch, cycle's seed, nth's concrete branch). some is already lazy (overlay). realized? reads the :realized flag without forcing. first/nth/take pull only as far as needed. Regression: deadlined (every?/not-every? pos? (range)) cases — would hang if the leak returned. Gate: conformance 249x3, lazy-infinite 42/42, fixpoint, self-host, specs+unit green. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/jolt/core.janet | 24 +++++++++++++++++++---- test/integration/lazy-infinite-test.janet | 2 ++ 2 files changed, 22 insertions(+), 4 deletions(-) diff --git a/src/jolt/core.janet b/src/jolt/core.janet index 65c2f92..d7d25cf 100644 --- a/src/jolt/core.janet +++ b/src/jolt/core.janet @@ -201,10 +201,26 @@ (= 0 (length coll)))))))))) (defn core-every? [pred coll] - (var result true) - (each x (realize-for-iteration coll) - (if (not (pred x)) (do (set result false) (break)))) - result) + # Short-circuit on the first false — and pull lazily so an infinite seq with an + # early false (e.g. (every? pos? (range))) returns rather than hanging. Walks + # cells via realize-ls directly (core-first/lazy-from are defined later). + (if (lazy-seq? coll) + (do + (var cur coll) (var result true) (var go true) + (while (and result go) + (let [cell (realize-ls cur)] + (if (or (nil? cell) (= :jolt/pending cell) (= 0 (length cell))) + (set go false) + (if (pred (in cell 0)) + (let [rt (in cell 1)] + (if (nil? rt) (set go false) (set cur (make-lazy-seq rt)))) + (set result false))))) + result) + (do + (var result true) + (each x (realize-for-iteration coll) + (if (not (pred x)) (do (set result false) (break)))) + result))) # ============================================================ # Math — Clojure semantics (variadic, / with one arg = reciprocal) diff --git a/test/integration/lazy-infinite-test.janet b/test/integration/lazy-infinite-test.janet index 4d94b30..a3fabfc 100644 --- a/test/integration/lazy-infinite-test.janet +++ b/test/integration/lazy-infinite-test.janet @@ -50,6 +50,8 @@ ["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))"] + ["every? short-circuits on inf" "false" "(every? pos? (range))"] + ["not-every? short-circuits on inf" "true" "(not-every? pos? (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 map-indexed vector range" "(quote ([0 0] [1 1] [2 2]))" "(take 3 (map-indexed vector (range)))"]