Search code examples
clojuremapreducetransducer

Is there a reducing function in Clojure that performs the equivalent of `first`?


I'm often writing code of the form

(->> init
     (map ...)
     (filter ...)
     (first))

When converting this into code that uses transducers I'll end up with something like

(transduce (comp (map ...) (filter ...)) (completing #(reduced %2)) nil init)

Writing (completing #(reduced %2)) instead of first doesn't sit well with me at all. It needlessly obscures a very straightforward task. Is there a more idiomatic way of performing this task?


Solution

  • I'd personally use your approach with a custom reducing function but here are some alternatives:

    (let [[x] (into [] (comp (map inc) (filter even?) (take 1)) [0 1])]
        x)
    

    Using destructing :/

    Or:

    (first (eduction (map inc) (filter even?) [0 1])
    

    Here you save on calling comp which is done for you. Though it's not super lazy. It'll realize up to 32 elements so it's potentially wasteful. Fixed with a (take 1):

    (first (eduction (map inc) (filter even?) (take 1) [0 1]))
    

    Overall a bit shorter and not too unclear compared to:

    (transduce (comp (map inc) (filter even?) (take 1)) (completing #(reduced %2)) nil [0 1])
    

    If you need this a bunch, then I'd probably NOT create a custom reducer function but instead a function similar to transduce that takes xform, coll as the argument and returns the first value. It's clearer what it does and you can give it a nice docstring. If you want to save on calling comp you can also make it similar to eduction:

    (defn single-xf
      "Returns the first item of transducing the xforms over collection"
      {:arglists '([xform* coll])}
      [& xforms]
      (transduce (apply comp (butlast xforms)) (completing #(reduced %2)) nil (last xforms)))
    

    Example:

    (single-xf (map inc) (filter even?) [0 1])