fix: transducers/reduce short-circuit over infinite seqs via reduced
transduce-reduce and core-reduce both called realize-for-iteration, fully realizing the coll before the reduce loop — so an infinite lazy seq hung before the reduced short-circuit could fire. (into [] (take 5) (range)) etc. never terminated. Add reduce-with-reduced, which steps a lazy seq one cell at a time (realize-ls/ls cell protocol), checking reduced? after each element so a take/ take-while transducer (or any reducing fn returning reduced) terminates over an infinite seq. Route transduce-reduce and both core-reduce arities through it; 2-arg reduce now seeds from the first element and reduces the rest lazily. spec: transducers/short-circuit + reduce/honors-reduced (13 cases). clojure-test-suite timeouts 7->6, pass 1683->1688. jpm test green. Fixes jolt-kxb.
This commit is contained in:
parent
ae2899ba61
commit
2885650ef6
3 changed files with 69 additions and 25 deletions
|
|
@ -27,3 +27,26 @@
|
|||
["sequence xform" "[2 3 4]" "(sequence (map inc) [1 2 3])"]
|
||||
["eduction" "[2 3 4]" "(into [] (eduction (map inc) [1 2 3]))"]
|
||||
["completing" "9" "(transduce (map inc) (completing +) 0 [1 2 3])"])
|
||||
|
||||
# A `take`/`take-while` transducer returns `reduced`, which must short-circuit
|
||||
# the reduction so transducing over an INFINITE seq terminates rather than
|
||||
# realizing it eagerly.
|
||||
(defspec "transducers / short-circuit over infinite seqs"
|
||||
["into take (range)" "[0 1 2 3 4]" "(into [] (take 5) (range))"]
|
||||
["transduce take (range)" "3" "(transduce (take 3) + 0 (range))"]
|
||||
["sequence take (range)" "[0 1 2 3 4]" "(sequence (take 5) (range))"]
|
||||
["take-while over (range)" "[0 1 2]" "(into [] (take-while (fn [x] (< x 3))) (range))"]
|
||||
["comp take over (range)" "[1 3 5]" "(into [] (comp (filter odd?) (take 3)) (range))"]
|
||||
["into take iterate" "[0 1 2 3 4]" "(into [] (take 5) (iterate inc 0))"])
|
||||
|
||||
# `reduce` itself honors `reduced`, so a reducing fn that returns `reduced`
|
||||
# terminates even over an infinite seq.
|
||||
(defspec "reduce / honors reduced"
|
||||
["reduced short-circuits inf" "105"
|
||||
"(reduce (fn [a x] (if (> a 100) (reduced a) (+ a x))) 0 (range))"]
|
||||
["reduce take inf" "10" "(reduce + (take 5 (range)))"]
|
||||
["reduce no-init first elem" "6" "(reduce + [1 2 3])"]
|
||||
["reduce no-init single" "42" "(reduce + [42])"]
|
||||
["reduce empty calls f" "0" "(reduce + [])"]
|
||||
["reduce with-init" "16" "(reduce + 10 [1 2 3])"]
|
||||
["reduce reduced immediate" ":x" "(reduce (fn [a x] (reduced :x)) :init [1 2 3])"])
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue