diff --git a/.beads/interactions.jsonl b/.beads/interactions.jsonl index cc5a56a..19cbd6e 100644 --- a/.beads/interactions.jsonl +++ b/.beads/interactions.jsonl @@ -1,2 +1,4 @@ {"id":"int-621ea914","kind":"field_change","created_at":"2026-06-04T17:50:54.012588Z","actor":"Yogthos","issue_id":"jolt-x8s","extra":{"field":"status","new_value":"closed","old_value":"open"}} {"id":"int-978620fa","kind":"field_change","created_at":"2026-06-04T17:59:35.53184Z","actor":"Yogthos","issue_id":"jolt-lp5","extra":{"field":"status","new_value":"closed","old_value":"open"}} +{"id":"int-11c77978","kind":"field_change","created_at":"2026-06-04T18:06:01.464313Z","actor":"Yogthos","issue_id":"jolt-tws","extra":{"field":"status","new_value":"closed","old_value":"open"}} +{"id":"int-2eef7613","kind":"field_change","created_at":"2026-06-04T18:06:02.544998Z","actor":"Yogthos","issue_id":"jolt-wec","extra":{"field":"status","new_value":"closed","old_value":"open"}} diff --git a/.beads/issues.jsonl b/.beads/issues.jsonl index c8fa589..e5cece0 100644 --- a/.beads/issues.jsonl +++ b/.beads/issues.jsonl @@ -1,6 +1,6 @@ {"_type":"issue","id":"jolt-lp5","title":"CRITICAL: vec/into over lazy-seq leaks PV struct; into {} builds int keys","status":"closed","priority":1,"issue_type":"bug","owner":"yogthos@gmail.com","created_at":"2026-06-04T17:46:15Z","created_by":"Yogthos","updated_at":"2026-06-04T17:59:35Z","closed_at":"2026-06-04T17:59:35Z","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"jolt-nte","title":"Build phased Clojure conformance harness (extracted assertions)","status":"open","priority":1,"issue_type":"task","owner":"yogthos@gmail.com","created_at":"2026-06-04T17:46:15Z","created_by":"Yogthos","updated_at":"2026-06-04T17:46:15Z","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"jolt-tws","title":"CRITICAL: iterate arity bug","status":"open","priority":1,"issue_type":"bug","owner":"yogthos@gmail.com","created_at":"2026-06-04T17:46:14Z","created_by":"Yogthos","updated_at":"2026-06-04T17:46:14Z","dependency_count":0,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"jolt-tws","title":"CRITICAL: iterate arity bug","status":"closed","priority":1,"issue_type":"bug","owner":"yogthos@gmail.com","created_at":"2026-06-04T17:46:14Z","created_by":"Yogthos","updated_at":"2026-06-04T18:06:01Z","closed_at":"2026-06-04T18:06:01Z","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"jolt-x8s","title":"CRITICAL: collections not callable as IFn (vector/map/set)","status":"closed","priority":1,"issue_type":"bug","owner":"yogthos@gmail.com","created_at":"2026-06-04T17:46:14Z","created_by":"Yogthos","updated_at":"2026-06-04T17:50:54Z","closed_at":"2026-06-04T17:50:54Z","dependency_count":0,"dependent_count":0,"comment_count":0} {"_type":"issue","id":"jolt-alz","title":"CRITICAL: self-referential lazy-seq/lazy-cat yields only literal prefix","status":"open","priority":1,"issue_type":"bug","owner":"yogthos@gmail.com","created_at":"2026-06-04T17:46:13Z","created_by":"Yogthos","updated_at":"2026-06-04T17:46:13Z","dependency_count":0,"dependent_count":0,"comment_count":0} -{"_type":"issue","id":"jolt-wec","title":"CRITICAL: multi-collection map returns unrealized thunk","status":"open","priority":1,"issue_type":"bug","owner":"yogthos@gmail.com","created_at":"2026-06-04T17:46:12Z","created_by":"Yogthos","updated_at":"2026-06-04T17:46:12Z","dependency_count":0,"dependent_count":0,"comment_count":0} +{"_type":"issue","id":"jolt-wec","title":"CRITICAL: multi-collection map returns unrealized thunk","status":"closed","priority":1,"issue_type":"bug","owner":"yogthos@gmail.com","created_at":"2026-06-04T17:46:12Z","created_by":"Yogthos","updated_at":"2026-06-04T18:06:02Z","closed_at":"2026-06-04T18:06:02Z","dependency_count":0,"dependent_count":0,"comment_count":0} diff --git a/src/jolt/core.janet b/src/jolt/core.janet index b38ea63..ddac0ae 100644 --- a/src/jolt/core.janet +++ b/src/jolt/core.janet @@ -326,15 +326,30 @@ # ============================================================ +(defn- seq-done? + "True when cursor c (a lazy-seq or a concrete collection) is exhausted. + Uses cell realization for lazy-seqs so nil elements don't end the seq early." + [c] + (if (lazy-seq? c) + (let [cell (realize-ls c)] + (or (nil? cell) (= :jolt/pending cell) (= 0 (length cell)))) + (or (nil? c) (= 0 (length c))))) + (defn core-map [f & colls] (if (= 1 (length colls)) - # Single-collection: eagerly realized - (let [c (realize-for-iteration (colls 0)) - result (do - (var res @[]) - (each x c (array/push res (f x))) - res)] - (if (tuple? c) (tuple/slice (tuple ;result)) result)) + (let [coll (colls 0)] + (if (lazy-seq? coll) + # Lazy input: stay lazy so infinite/self-referential seqs work. + (do + (defn mstep [c] + (fn [] + (if (seq-done? c) nil + @[(f (core-first c)) (mstep (core-rest c))]))) + (make-lazy-seq (mstep coll))) + # Concrete collection: eager (preserves tuple/array representation). + (let [c (if (set? coll) (phs-seq coll) coll) + result (do (var res @[]) (each x c (array/push res (f x))) res)] + (if (tuple? c) (tuple/slice (tuple ;result)) result)))) # Multi-collection: lazy-seq with per-element independent state (let [init-cs (array/new-filled (length colls) nil) init-idxs (array/new-filled (length colls) 0) @@ -383,7 +398,7 @@ (defn core-filter [pred coll] (var result @[]) - (each x (if (set? coll) (phs-seq coll) coll) + (each x (if (set? coll) (phs-seq coll) (realize-for-iteration coll)) (if (pred x) (array/push result x))) (if (tuple? coll) (tuple/slice (tuple ;result)) result)) @@ -394,7 +409,7 @@ (fn [& args] (case (length args) 2 (let [f (args 0) coll (args 1) - coll (if (set? coll) (phs-seq coll) coll)] + coll (if (set? coll) (phs-seq coll) (realize-for-iteration coll))] (if (= 0 (length coll)) (f) (do @@ -405,7 +420,7 @@ (++ i)) acc))) 3 (let [f (args 0) val (args 1) coll (args 2) - coll (if (set? coll) (phs-seq coll) coll)] + coll (if (set? coll) (phs-seq coll) (realize-for-iteration coll))] (var acc val) (each x coll (set acc (f acc x))) acc) @@ -637,15 +652,20 @@ (def core-range (fn [& args] - (let [start (if (> (length args) 1) (args 0) 0) - end (if (> (length args) 1) (args 1) (args 0)) - step (if (> (length args) 2) (args 2) 1)] - (var result @[]) - (var i start) - (while (if (pos? step) (< i end) (> i end)) - (array/push result i) - (+= i step)) - (tuple/slice (tuple ;result))))) + (if (= 0 (length args)) + # (range) — infinite lazy sequence 0, 1, 2, ... + (do + (defn rstep [i] (fn [] @[i (rstep (+ i 1))])) + (make-lazy-seq (rstep 0))) + (let [start (if (> (length args) 1) (args 0) 0) + end (if (> (length args) 1) (args 1) (args 0)) + step (if (> (length args) 2) (args 2) 1)] + (var result @[]) + (var i start) + (while (if (pos? step) (< i end) (> i end)) + (array/push result i) + (+= i step)) + (tuple/slice (tuple ;result)))))) (def core-repeat (fn [n x] (var result @[]) @@ -656,17 +676,9 @@ result)) (defn core-iterate [f x] - "Macro: (iterate f x) → lazy infinite sequence x, (f x), (f (f x)), ..." - (def sym-x (gensym "x")) - (def sym-f (gensym "f")) - @[{:jolt/type :symbol :ns nil :name "lazy-seq"} - @[{:jolt/type :symbol :ns nil :name "let*"} - @[sym-x x sym-f f] - @[{:jolt/type :symbol :ns nil :name "cons"} - sym-x - @[{:jolt/type :symbol :ns nil :name "iterate"} - sym-f - @[{:jolt/type :symbol :ns nil :name sym-f} sym-x]]]]]) + "Lazy infinite sequence x, (f x), (f (f x)), ..." + (defn istep [v] (fn [] @[v (istep (f v))])) + (make-lazy-seq (istep x))) (defn core-repeatedly [n f] (var result @[])