# Specification: transducers. (use ../support/harness) (defspec "transducers / into" ["map xform" "[2 3 4]" "(into [] (map inc) [1 2 3])"] ["filter xform" "[2 4]" "(into [] (filter even?) [1 2 3 4])"] ["remove xform" "[1 3]" "(into [] (remove even?) [1 2 3 4])"] ["take xform" "[1 2]" "(into [] (take 2) [1 2 3 4])"] ["drop xform" "[3 4]" "(into [] (drop 2) [1 2 3 4])"] ["take-while xform" "[1 2]" "(into [] (take-while (fn [x] (< x 3))) [1 2 3 1])"] ["keep xform" "[1 3]" "(into [] (keep (fn [x] (if (odd? x) x nil))) [1 2 3 4])"] ["map-indexed xform" "[[0 :a] [1 :b]]" "(into [] (map-indexed vector) [:a :b])"] ["mapcat xform" "[1 1 2 2]" "(into [] (mapcat (fn [x] [x x])) [1 2])"] ["cat xform" "[1 2 3 4]" "(into [] cat [[1 2] [3 4]])"] ["into a set" "#{2 3 4}" "(into #{} (map inc) [1 2 3])"]) # transducer comp applies left-to-right: (comp (map a) (filter b)) maps then filters (defspec "transducers / compose" ["comp map+filter" "[2 4 6 8]" "(into [] (comp (map (fn [x] (* x 2))) (filter even?)) [1 2 3 4])"] ["comp filter+map" "[2 4]" "(into [] (comp (filter odd?) (map inc)) [1 2 3 4])"] ["comp three" "[2]" "(into [] (comp (map inc) (filter even?) (take 1)) [1 2 3 4])"]) (defspec "transducers / transduce & sequence" ["transduce sum" "9" "(transduce (map inc) + [1 2 3])"] ["transduce init" "19" "(transduce (map inc) + 10 [1 2 3])"] ["transduce filter" "6" "(transduce (filter even?) + [1 2 3 4])"] ["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])"]) # halt-when replaces the WHOLE reduction result with the halting input (or # with (retf acc input)) — Clojure's ::halt map protocol, unwrapped by the # transducer's completion arity. (defspec "transducers / halt-when" ["halt returns the halting input" "7" "(transduce (halt-when (fn [x] (> x 5))) conj [1 2 7 3])"] ["no halt is a plain reduction" "[1 2 3]" "(transduce (halt-when (fn [x] (> x 5))) conj [1 2 3])"] ["retf combines acc and input" "[[1 2] 7]" "(transduce (halt-when (fn [x] (> x 5)) (fn [r i] [r i])) conj [1 2 7 3])"] ["halt-when through into" "3" "(into [] (halt-when odd?) [2 4 3 6])"]) # 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])"]) # into/transduce/eduction are overlay fns now (seed-shrink round 5): into # takes a transient fast path for vectors and preserves metadata; eduction # stays eager (documented divergence). (defspec "transducers / into & eduction (overlay)" ["into list prepends" "(quote (4 3 1 2))" "(into (quote (1 2)) [3 4])"] ["into sorted-map" "{1 :a, 2 :b}" "(into (sorted-map) [[2 :b] [1 :a]])"] ["into from map entry" "[:a 1]" "(into [] (first {:a 1}))"] ["into xform on map" "{:a 2}" "(into {} (map (fn [e] [(key e) (inc (val e))])) {:a 1})"] ["eduction multiple xforms" "[4]" "(into [] (eduction (filter odd?) (map inc) [2 3 4]))"] ["->Eduction" "[2 3]" "(->Eduction (map inc) [1 2])"] ["transduce no init uses (f)" "5" "(transduce (map inc) + [1 2])"])