Step 4: evaluator eager assumptions — lazy rest + lazy mapcat
Fix & rest destructuring (evaluator.janet): when the original value is a lazy-seq, derive & rest by walking ls-rest vi steps instead of slicing the eagerly-realized array from d-realize. Rewrite core-mapcat as a lazy state machine (core.janet): step through input colls one element at a time, call f on each tuple, then yield from f's result collection. No apply-forcing — all input colls are walked lazily via lazy-from + seq-done?. Add mapcat to core-renames (compiler.janet) and remove from Clojure overlay (10-seq.clj) — compile mode now emits direct calls to the lazy core-mapcat, fixing the pre-existing protocol-on-record compile error. Tests: re-enabled mapcat infinite harness case, added 2 & rest laziness cases. 21/21 lazy-infinite, 229x3 conformance, 32/32 specs.
This commit is contained in:
parent
ff8ffb8cd6
commit
42da5cef9a
5 changed files with 60 additions and 26 deletions
|
|
@ -22,8 +22,3 @@
|
|||
(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))))
|
||||
|
|
|
|||
|
|
@ -97,6 +97,7 @@
|
|||
"take-while" "core-take-while"
|
||||
"drop-while" "core-drop-while"
|
||||
"nth" "core-nth"
|
||||
"mapcat" "core-mapcat"
|
||||
"list" "core-list"
|
||||
"name" "core-name"
|
||||
"subs" "core-subs"
|
||||
|
|
|
|||
|
|
@ -1134,17 +1134,44 @@
|
|||
(each x (realize-for-iteration (f (a 1)))
|
||||
(set acc (rf acc x)))
|
||||
acc))))
|
||||
# collection arity: map f over colls, then concatenate. A non-seqable
|
||||
# result counts as a single element (this leniency is what jolt's `for`
|
||||
# expansion relies on for :let on the last binding, whose body yields a
|
||||
# scalar rather than a seq).
|
||||
(let [mapped (realize-for-iteration (core-apply core-map f colls))
|
||||
seqs (map (fn [item]
|
||||
(if (or (tuple? item) (array? item) (pvec? item)
|
||||
(lazy-seq? item) (set? item))
|
||||
item (tuple item)))
|
||||
mapped)]
|
||||
(core-apply core-concat seqs))))
|
||||
# collection arity: direct lazy implementation. Pull one element
|
||||
# from each input coll, apply f, then yield elements from f's result.
|
||||
# No apply-forcing — walk input colls lazily element-by-element.
|
||||
(do
|
||||
(var n (length colls))
|
||||
(var init-cs @[])
|
||||
(var i 0)
|
||||
(while (< i n)
|
||||
(array/push init-cs (lazy-from (in colls i)))
|
||||
(++ i))
|
||||
(defn step [cs res]
|
||||
(fn []
|
||||
(var cursors cs) (var cur-res res) (var hit nil) (var ok false)
|
||||
(while (not ok)
|
||||
(if (nil? cur-res)
|
||||
(do
|
||||
(var args @[]) (var next-cs @[]) (var exhausted false) (var j 0)
|
||||
(while (and (< j n) (not exhausted))
|
||||
(let [c (in cursors j)]
|
||||
(if (seq-done? c) (set exhausted true)
|
||||
(do
|
||||
(array/push args (ls-first c))
|
||||
(array/push next-cs (ls-rest c)))))
|
||||
(++ j))
|
||||
(if exhausted (break))
|
||||
(let [r (apply f args)]
|
||||
(set cursors next-cs)
|
||||
(set cur-res (if (or (nil? r) (tuple? r) (array? r)
|
||||
(lazy-seq? r) (pvec? r) (set? r) (plist? r))
|
||||
(lazy-from r)
|
||||
(lazy-from (tuple r))))))
|
||||
(if (seq-done? cur-res)
|
||||
(set cur-res nil)
|
||||
(let [val (ls-first cur-res) rest (ls-rest cur-res)]
|
||||
(set hit @[val (step cursors rest)])
|
||||
(set ok true)))))
|
||||
(if ok hit nil)))
|
||||
(make-lazy-seq (step init-cs nil)))))
|
||||
|
||||
(defn core-reverse [coll]
|
||||
(if (nil? coll) @[]
|
||||
|
|
|
|||
|
|
@ -552,11 +552,21 @@
|
|||
# & rest
|
||||
(and (struct? elem) (= :symbol (elem :jolt/type)) (= "&" (elem :name)))
|
||||
(do
|
||||
# rest binds a seq (jolt list = array), per Clojure semantics
|
||||
# rest binds a seq (jolt list = array), per Clojure semantics.
|
||||
# For lazy-seqs, preserve laziness: walk vi steps via ls-rest
|
||||
# instead of slicing the eagerly-realized array.
|
||||
(destructure-bind ctx bindings (in pat (+ di 1))
|
||||
(if (lazy-seq? val)
|
||||
(do
|
||||
(var c val) (var i 0)
|
||||
(while (< i vi)
|
||||
(let [nxt (ls-rest c)]
|
||||
(if (nil? nxt) (break)
|
||||
(do (set c nxt) (++ i)))))
|
||||
c)
|
||||
(if (and seqable? (< vi (length rv)))
|
||||
(array/slice (if (tuple? rv) (array/slice rv) rv) vi)
|
||||
@[]))
|
||||
@[])))
|
||||
(set di (+ di 2)))
|
||||
# :as whole
|
||||
(= elem :as)
|
||||
|
|
|
|||
|
|
@ -52,8 +52,9 @@
|
|||
["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 distinct cycle" "(quote (1 2 3))" "(take 3 (distinct (cycle [1 2 1 3 1])))"]
|
||||
# mapcat on infinite inputs hangs (apply forces lazy result, needs Step 4).
|
||||
# ["take 6 mapcat dup range" "(quote (0 0 1 1 2 2))" "(take 6 (mapcat (fn [x] [x x]) (range)))"]
|
||||
["take 6 mapcat dup range" "(quote (0 0 1 1 2 2))" "(take 6 (mapcat (fn [x] [x x]) (range)))"]
|
||||
["first rest lazy" "1" "(let [[a & r] (range)] (first r))"]
|
||||
["take 3 rest lazy" "(quote (1 2 3))" "(let [[a & r] (range)] (take 3 r))"]
|
||||
["take 3 take-nth 2 range" "(quote (0 2 4))" "(take 3 (take-nth 2 (range)))"]
|
||||
["take 3 interpose :x range" "(quote (0 :x 1))" "(take 3 (interpose :x (range)))"]
|
||||
["take 3 map vector range iterate" "(quote ([0 100] [1 101] [2 102]))" "(take 3 (map vector (range) (iterate inc 100)))"]
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue