clojurereducetransducer

Clojure reduce transducer


I am looking for a simple example of transducers with a reducing function. I was hoping that the following would return a transducing function, since (filter odd?) works that way :

(def sum (reduce +))
clojure.lang.ArityException: Wrong number of args (1) passed to: core$reduce

My current understanding of transducers is that by omitting the collection argument, we get back a transducing function that we can compose with other transducing functions. Why is it different for filter and reduce ?


Solution

  • The reduce function doesn't return a transducer. It's that way because of reduce is the function which returns a value which could be sequence. Other function like filter or map always returns sequences(even empty), that allows to combine this functions.

    For combining something with a reduce function, you can use a reducer library which gives a functionality similar to what you want to do (if I correctly understood this).

    ###UPD Ok, my answer is a bit confusing. First of all let's take a look on an how filter, map and many other functions works: it's not surprise, that all this function is based on reduce, it's an reduction function(in that way, that they doesn't create a collection with bigger size that input one). So, if you reduce some coll in any way - You can combine your reduction to pass reducible value from reducible coll between all the reduction function to get final value. It is a great way to improve performance, because part of values will hopefully nil somehow (as a part of transformation), and there is only one logical cycle (I mean loop, you iterate over sequence only one time and pass every value through all the transformation). So, why the reduce function is so different, because everything built on it?

    All transducer based on a simple and effective idea which in my opinion looks like sieve. But the reduction may be only for last step, because of the only one value as the result. So, the only way you can use reduce here is to provide a coll and a reduction form. Reduce in sieve analogy is like funnel under the sieve: You take your collection, throw it to some function like map and filter and take - and as you can see the size of new collection, which is the result of transformation, will never be bigger than the input collection. So the last step may be a reduce which takes a sieved collection and takes one value based on everything what was done.

    There is also a different function, which allows you to combine transducers and reducers - transducer, but it's also require a function, because it's like an entry point and the last step in our sieve.

    The reducers library is similar to transducers and also allow reduce as a last step. It's just another approach to make the same as a transducer.

    To achieve what you want to do you can use partial function instead. It would be like this:

    (def sum
      (partial reduce +'))
    
    (sum [1 2 3])
    

    will return obvious answer of 6