Reducers primarily have two benefits: 1. You don't need to create intermediate seqs 2. You can use them to perform a parallel fold
When you use clojure.core/map, it creates a lazy seq. When you use clojure.core.reducers/map, it returns a small reified object that implements CollReduce. Perhaps the best way to understand what's going on is to start with the normal seq functions. For instance, consider this code: (let [ys (map inc xs)] (filter even? ys)) In this example, an intermediate seq, ys, needs to be constructed. We can avoid this intermediate seq by using a reduce that combines both steps: (reduce (fn [r x] (if (even? x) (conj r (inc x)) r) [] xs) The problem with this approach is that it's rather complected. What we need is something that resolves to a reduce, but can be combined like map and filter. This is where reducers come in. The main idea is to factor out that pesky conj, so we can separating the reduction from the implementation details of the collection. So we can take the inner reducing function: (fn [r x] (if (even? x) (conj r (inc x)) r) And then factor out conj: (fn [f] (fn [r x] (if (even? x) (f r (inc x)) r)) We can then split out the filter and map to get two functions (fn [f] (fn [r x] (if (even? x) (f r x) r)) (fn [f] (fn [r x] (f r (inc x))) And then take out even? and inc to get generic filter and map functions: (defn filterer [xf] (fn [f] (fn [r x] (if (xf x) (f r x) r)) (defn mapper [xf] (fn [f] (fn [r x] (f r (xf x))) So now we have the essence of map and filter, but we've removed the implementation details of the collection. Next we just need to figure out how to use these highly abstracted functions. If we just want to use one of the functions, we can do so like this: ((mapper inc) conj) This returns a function: (fn [r x] (conj r (inc x))) If we want to combine map and filter, we need an expression like: (fn [r x] (if (even? x) (conj r (inc x)) r)) We can do this by passing the result of the mapping function into filterer as f: ((filterer even?) ((mapper inc) conj)) Or, we could use comp to compose the two functions, then apply conj, since (f (g x)) is the same as ((comp f g) x): ((comp (filterer even?) (mapper inc)) conj)) Now we can can finally create our efficient map/filter in a clean way: (let [f (comp (filterer even?) (mapper inc))] (reduce (f conj) [] xs)) The reducer library goes one step further, and uses protocols to make it a little nicer to use, but the mechanics are more or less the same. - James On 24 September 2014 15:30, Hussein B. <hubaghd...@gmail.com> wrote: > To elaborate more, > I know that with reducers, map for example isn't going to create the > resulting sequence by using cons. That is clear to me. > But, if the collections is going to call cons while reducing itself, then > I'm not sure what is the benefit of reducers (besides it makes sense and > makes a nice abstraction). > > Thanks. > > On Wednesday, September 24, 2014 2:58:18 PM UTC+2, Aleš Roubíček wrote: > >> Resulting function is passed to reduction function as an recipe, how to >> process the data. Collections implements CollReduce protocol. When you call >> reduce function it will delegate the work to concrete implementation of the >> protocol. > > -- > You received this message because you are subscribed to the Google > Groups "Clojure" group. > To post to this group, send email to clojure@googlegroups.com > Note that posts from new members are moderated - please be patient with > your first post. > To unsubscribe from this group, send email to > clojure+unsubscr...@googlegroups.com > For more options, visit this group at > http://groups.google.com/group/clojure?hl=en > --- > You received this message because you are subscribed to the Google Groups > "Clojure" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to clojure+unsubscr...@googlegroups.com. > For more options, visit https://groups.google.com/d/optout. > -- You received this message because you are subscribed to the Google Groups "Clojure" group. To post to this group, send email to clojure@googlegroups.com Note that posts from new members are moderated - please be patient with your first post. To unsubscribe from this group, send email to clojure+unsubscr...@googlegroups.com For more options, visit this group at http://groups.google.com/group/clojure?hl=en --- You received this message because you are subscribed to the Google Groups "Clojure" group. To unsubscribe from this group and stop receiving emails from it, send an email to clojure+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.