A Clojure folder enhances a collection with custom reducing and folding behavior. It receives a collection and an xf function; xf receives the original reducing function and returns a replacement two-argument reducer. section 7.1.2
Use folder when a transformation must participate in r/fold as well as ordinary reduction. It intercepts reducef behavior, but not combinef, so the reducer must remain compatible with the fold’s partitioning and combination strategy. section 7.1.2
Filtering values inside a fold
A transforming function can pass only keys divisible by 10 to the downstream reducer: (r/folder (zipmap (range 100) (range 100)) (fn [rf] (fn [m k v] (if (zero? (mod k 10)) (rf m k v) m)))). Folding this collection with a map-combining monoid produces entries such as {0 3, 10 13, 20 23, ..., 90 93}. section 7.1.2
Standard reducers such as map, mapcat, filter, remove, flatten, and cat are foldable. take-while, take, and drop are not inherently foldable; custom folder implementations can address stateful behavior when parallel folding requires it. section 7.1.2
Listing 7.2. → Transforming Functions, Reducing Functions, Collection Reduce, Folding
(reducer [coll xf]) (folder [coll xf])
Compare the reducer and folder signatures before choosing collection-level reduction or folding enhancement. section 7.1.2
(require '[clojure.core.reducers :as r]) ; #1
(defn divisible-by-10 [current-reducing-fn] ; #2
(fn [acc el]
(if (zero? (mod el 10))
(current-reducing-fn acc el)
acc)))
(into [] ; #3
(r/reducer
(range 100)
divisible-by-10))
;; [0 10 20 30 40 50 60 70 80 90]
(r/fold ; #4
(r/monoid merge (constantly {}))
(fn [m k v] (assoc m k (+ 3 v)))
(r/folder
(zipmap (range 100) (range 100))
(fn [rf] (fn [m k v] (if (zero? (mod k 10)) (rf m k v) m)))))
;; {0 3, 70 73, 20 23, 60 63, 50 53, 40 43, 90 93, 30 33, 10 13, 80 83}
Run a compact folder example that filters values during r/fold and combines the retained results. section 7.1.2
