This is maybe as good a time as any to discuss the usual alternative presentation of transducers that I find is a far gentler introduction.
A transducer is simply a function of the form `a -> List<b>`. Yes this is fully polymorphic, i.e. it holds even for transducers that only operate over just lists.
In this case `mapping` is just
This lens views a transducer through the lens of the `eduction` function as a more souped up `map`. Whereas with a normal `map` you only get to use a function `a -> b`, which means you can't change the underlying structure, with `eduction` you get to use `a -> List<b>` (again a transducer), where you "keep" any elements that are in the output list and you "discard" any elements not in the output list.
So e.g. `mapping` would be:
(defn mapping [f] (fn [x] [(f x)]))
or in Python
def mapping(f):
return lambda x: [f(x)]
and `filtering` would be:
(defn filtering [f] (fn [x] [if (f x) [x] []]))
or in Python
def filtering(f):
return lambda x: [x] if f(x) else []
Transducers are IMHO one of the most under-appreciated features of Clojure. If you want a really good intro, watch Rich Hickey's talk about transducers: https://www.youtube.com/watch?v=6mTbuzafcII (Rich is an excellent speaker and most of his talks are really worth watching, even if you don't use Clojure).
The thing about transducers is that once you start using them, the abstractions click in your mind and you start using them more and more in your code. Many things our software does can be looked at as pipelines, and transducers let you write composable functions and put them together into pipelines. As you see more pipelines in your code, you will write those composable functions and reuse them in various places.
Experienced Clojure programmers will rarely use loops, for me transducers are the #1 choice whenever I have to process a collection of any kind.
Their efficiency (no intermediate collections!) is a nice bonus — you get both high-level composable code and efficiency, which is incredible.
One thing I dislike about transducers is when I need a stateful one: these are hard to understand and very difficult to write. I rarely do this, except when I really want to stick to the transducer abstraction and I have a couple of hours to spend on a puzzle. But you rarely need to write your own stateful transducers, usually the built-in ones are enough (things like take/drop).
A popular noob error in Clojure is to get really, really excited about using reduce and trying to use it to replace for loops. Maybe someone wants to sum up every other odd number and they build some horrible reducer to do that which manages its own state in the reduction object. It leads to ugly code. Reduce and it's colleague map are most powerful when the underlying collection could have been be shuffled and it wouldn't matter much - or at least where the state to be managed in the reduce is trivial.
So something to note about transduce is that it looks a lot like reduce but suddenly the examples [0] start being more complex functions where some elements of the collection get removed, order matters and state begins to appear during the fold. Functions like `take`, `filter`, `partition`, `interpose`, `dedupe`, etc, etc.
As with many things in the functional world (cough monads) I feel the explanations don't make a lot of sense before meeting the problem they solve in the wild. As with a lot of Clojure's better parts transducers are a state management tool.
A transducer is simply a function of the form `a -> List<b>`. Yes this is fully polymorphic, i.e. it holds even for transducers that only operate over just lists.
In this case `mapping` is just
This lens views a transducer through the lens of the `eduction` function as a more souped up `map`. Whereas with a normal `map` you only get to use a function `a -> b`, which means you can't change the underlying structure, with `eduction` you get to use `a -> List<b>` (again a transducer), where you "keep" any elements that are in the output list and you "discard" any elements not in the output list.
So e.g. `mapping` would be:
or in Python and `filtering` would be: or in Python In my opinion way clearer and easier!For more details on the full equivalence see https://news.ycombinator.com/item?id=27778423
The current presentation of transducers has always felt like a wart in Clojure.
It starting to be quite some time ago, but I can answer some questions if you have any.
The thing about transducers is that once you start using them, the abstractions click in your mind and you start using them more and more in your code. Many things our software does can be looked at as pipelines, and transducers let you write composable functions and put them together into pipelines. As you see more pipelines in your code, you will write those composable functions and reuse them in various places.
Experienced Clojure programmers will rarely use loops, for me transducers are the #1 choice whenever I have to process a collection of any kind.
Their efficiency (no intermediate collections!) is a nice bonus — you get both high-level composable code and efficiency, which is incredible.
One thing I dislike about transducers is when I need a stateful one: these are hard to understand and very difficult to write. I rarely do this, except when I really want to stick to the transducer abstraction and I have a couple of hours to spend on a puzzle. But you rarely need to write your own stateful transducers, usually the built-in ones are enough (things like take/drop).
So something to note about transduce is that it looks a lot like reduce but suddenly the examples [0] start being more complex functions where some elements of the collection get removed, order matters and state begins to appear during the fold. Functions like `take`, `filter`, `partition`, `interpose`, `dedupe`, etc, etc.
As with many things in the functional world (cough monads) I feel the explanations don't make a lot of sense before meeting the problem they solve in the wild. As with a lot of Clojure's better parts transducers are a state management tool.
[0] https://clojure.org/reference/transducers