Using transducers is really easy and intuitive (with "comp" letting you compose a pipeline of transformations in a readable way).
Writing custom transducers, especially stateful transducers is really difficult. But that's not something you'll do often. My 10kLOC complex app has three stateful transducers that I wrote.
I think transducers are an under-appreciated aspect of Clojure. They are an extremely valuable and flexible tool, and have allowed me to write reusable and composable code and tackle significant complexity, all with great performance.
Transducers aren’t just faster, they offer more functionality, with the ability to reuse the logic no matter where your inputs and outputs are coming from. So it’s no real surprise that there’s more implementation complexity. Client code isn’t much more complex, and arguably lower mental overhead because you can give stacks of transducers names without having to introduce a whole new function with a sequence as an argument.
Obviously in languages that can reliably perform stream fusion transparently, maybe you care less, but the abstraction isn’t just about the speedup.
Yup. And to be honest there’s a bunch of additional complexity in Clojure transducers that I very much dislike (all the reducing function stuff which is almost never actually used and which is secondary to the purpose of creating a sequence transform via function composition). But it’s a tradeoff you make for additional functionality or speed. Or you move complexity to reduce cognitive overhead for certain use cases. There’s rarely a free lunch.
Writing custom transducers, especially stateful transducers is really difficult. But that's not something you'll do often. My 10kLOC complex app has three stateful transducers that I wrote.
I think transducers are an under-appreciated aspect of Clojure. They are an extremely valuable and flexible tool, and have allowed me to write reusable and composable code and tackle significant complexity, all with great performance.