In Python, the (complex, generic) iter() protocol is how every container provides a method to iterate itself, and reduce is a trivial application of a reducer (like your add function) to a container by using the iter protocol.
In Clojure, it's the opposite: there is a reduce() protocol and every reducible container knows how to reduce itself. the traditional reduce function just takes a reducer and a reducible and performs the reduce protocol on it.
As there's a bunch of different kinds of containers with different rules, the best way to implement the reduce protocol on them is different for each, and there might be weird specialized reducers that are parallel or asynchronous or lazy or whatever.
Transducers allow you to composibly transform reducers into different reducers, which can then be handed to the reduce protocol. As it turns out, most (all?) normal container->container operations, like map and filter, have corresponding transducers.
Here's the good part: if you have a reduce protocol and a complete set of tranducers, containers don't need to be mappable. The map(fn, iterable) function needs to know how to iterate; mapping(fn) doesn't care about containers at all, and is fully general to mapping any reducible for free. So you can write a transducer to produce the effect of any map or filter-like operation without touching iter().
As an added bonus, the code is more efficient:
reduce( add, map( lambda x: x + 1, xrange(10**9) ), 0 )
eagerly builds a gigantic mapped list (barring sophisticated laziness or loop-fusion optimizations), but reduce( mapping( lambda x: x + 1 )(add), xrange(10**9), 0 )
is equivalent and trivially runs in O(1) space on one element of xrange at a time.PS: python translation of mapping from http://clojure.com/blog/2012/05/15/anatomy-of-reducer.html converted to named functions to be more pythonic:
def mapping( transformation ):
def transducer( reducer ):
def new_reducer( accum, next ):
return reducer(accum, transformation(next) )
return new_reducer
return transducer