diff --git a/src/jolt/core.janet b/src/jolt/core.janet index 4fcfb0d..3f7be35 100644 --- a/src/jolt/core.janet +++ b/src/jolt/core.janet @@ -448,7 +448,9 @@ (if (and (indexed? r) (= 2 (length r)) (function? (in r 1))) r (coll->cells r))) - (if (lazy-seq? c) (realize-ls c) + (if (lazy-seq? c) + (let [cell (realize-ls c)] + (if (= :jolt/pending cell) nil cell)) (if (indexed? c) (if (= 0 (length c)) nil (if (and (= 2 (length c)) (function? (in c 1))) @@ -461,34 +463,21 @@ nil))))) (defn core-concat [& colls] - "Lazy concatenation — returns a lazy-seq that yields elements one at a time. - Fully functional: each rest thunk captures its own state, so multiple access - paths (e.g. fib-seq used simultaneously in (rest fib-seq) and fib-seq) work - without shared-mutable-state corruption." - (defn step [cs] - "Return a thunk that produces nil (end) or @[value, rest-thunk]." - (if (= 0 (length cs)) - (fn [] nil) - (let [c (in cs 0) - remaining (array/slice cs 1)] + "Lazy concatenation — returns a lazy-seq that yields elements one at a time." + (var cs (if (tuple? colls) (array/slice colls) colls)) + (var cur nil) + (defn next-cell [] + (var cell (coll->cells cur)) + (while (and (nil? cell) (not (nil? cs)) (> (length cs) 0)) + (set cur (in cs 0)) + (set cs (array/slice cs 1)) + (set cell (coll->cells cur))) + (if (nil? cell) nil + @[(in cell 0) (fn [] - (let [cell (coll->cells c)] - (if (nil? cell) - ((step remaining)) - (let [value (in cell 0) - rest-fn (in cell 1)] - @[value - (fn [] - (if (nil? rest-fn) - ((step remaining)) - (let [new-cs (array/new-filled (+ 1 (length remaining)) nil)] - (put new-cs 0 rest-fn) - (var i 0) - (while (< i (length remaining)) - (put new-cs (+ i 1) (in remaining i)) - (++ i)) - ((step new-cs)))))]))))))) - (make-lazy-seq (step (if (tuple? colls) (array/slice colls) colls)))) + (set cur (in cell 1)) + (next-cell))])) + (make-lazy-seq next-cell)) (defn core-reverse [coll] (if (nil? coll) @[] diff --git a/src/jolt/phm.janet b/src/jolt/phm.janet index 8a802d9..bc4e4a2 100644 --- a/src/jolt/phm.janet +++ b/src/jolt/phm.janet @@ -131,11 +131,12 @@ (defn realize-ls "Force a LazySeq cell. Returns nil (empty) or [first-val, rest-thunk]. If the thunk returns another lazy-seq, recursively realize it. - Detects self-referencing cycles by setting :realized before calling thunk." + Uses :jolt/pending sentinel to detect self-referencing cycles." [ls] (if (get ls :realized) (ls :val) (do + (put ls :val :jolt/pending) (put ls :realized true) (let [raw ((ls :fn)) v (if (lazy-seq? raw) (realize-ls raw) raw)] @@ -144,7 +145,7 @@ (defn ls-first [ls] (let [cell (realize-ls ls)] - (if (or (nil? cell) (= 0 (length cell))) nil (in cell 0)))) + (if (or (nil? cell) (= :jolt/pending cell) (= 0 (length cell))) nil (in cell 0)))) (defn ls-rest [ls] (let [cell (realize-ls ls)]