Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

If you’re going to do this, transducers let you avoid the intermediate sequences and are nearly just as readable:

    (into []
          (comp (filter :admin?)
                (filter :mod?))
          people)
As a side-effect, they are also more generic so you can reuse the transducer stack if you decide to use core.async or something.



So I find very few examples of people using transducers in production code these days. I agree they are very compelling from a theoretical programming standpoint, and I used them heavily for about a year for that reason. However, it clearly took me far longer to debug transducing code compared to traditional code, so these days I only use them when absolutely necessary for optimization purposes.


Interesting, I find the ergonomics of transducers a lot better than the threading macros, especially because it’s a more generic interface. Also, they seem to be an ideal point in the lazy/strict evaluation continuum: they compose like lazy functions (I.e. if you have (take 3), you’ll only get three elements even with an infinite input stream but they avoid the unpredictability of lazy functions like map because the actual process is run eagerly (unless this doesn’t make sense for the output datatype e.g. a core async channel.).

I’d also be a bit careful about judging popularity from open source codebases too: they are used heavily in all the production code based I maintain :) and I get the sense that they’re pretty widely used by the “silent majority” of clojure programmers.

My debugging strategy for them is basically what I do for threading macros anyways: (into [] (comp ... (map #(doto % (->> (println :it))) ....) inp)




Consider applying for YC's Fall 2025 batch! Applications are open till Aug 4

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: