‹ BackHN Continuity

Thread

Anecdotally, programmers dislike "reduce"

175 points · 283 comments · vinhnx

  1. Skeime · · focus · HN ↗
    I think this is because in an imperative language, `reduce` does not actually give you much over a `for item in collection` loop. With `map` and `filter`, you immediately learn something about the result (it's a list of the same length as the original, with each item only depending on the corresponding original item; it's a list containing some of the original elements unchanged and nothing else). This is useful, so `map` and `filter` are good.

    With `reduce`, the result could be anything, and in an imperative language, side effects are also possible. So it's just a loop with worse syntax.

    (Admittedly, in an imperative language, `map` and `filter` could also have side effects, though I think most people would consider this bad style.)

    1. Hackbraten · · focus · HN ↗
      I think that in every imperative language that offers `map`, `filter`, `reduce`, or similar, the written contract of this API should state that any higher-order function handed to it as an argument must be free from side effects.

      I think I’ve seen several language core APIs have this in their contract, e.g. `Stream#reduce` in Java [0] (emphasis mine):

      > accumulator - an *associative, non-interfering, stateless* function for combining two values

      [0]: <a href="https:&#x2F;&#x2F;docs.oracle.com&#x2F;javase&#x2F;8&#x2F;docs&#x2F;api&#x2F;java&#x2F;util&#x2F;stream&#x2F;Stream.html#reduce-T-java.util.function.BinaryOperator-" rel="nofollow">https:&#x2F;&#x2F;docs.oracle.com&#x2F;javase&#x2F;8&#x2F;docs&#x2F;api&#x2F;java&#x2F;util&#x2F;stream&#x2F;S...

      1. speedstyle · · focus · HN ↗
        In Rust these specifically take `FnMut`, a function which can update internal&#x2F;borrowed state, rather than `Fn` which can&#x27;t easily. In `map` or `filter` you shouldn&#x27;t rely on the iteration order so that&#x27;s not often useful – maybe something &#x27;logically&#x27; stateless but which needs a mutable connection&#x2F;threadpool&#x2F;cache, or eg a counter which is really an ancillary reduction. There&#x27;s even `inspect` which is explicitly for such side effects. In `fold`, the order is guaranteed and you could use it for a state machine, a fiddly `zip` with other mutable iterators, etc – something you need to perform the reduction, but which isn&#x27;t really an output, I think you could reasonably write either

            .fold(init, move |acc, x| {…})  &#x2F;&#x2F; or
            .fold((state, init), |(state, acc), x| {…}).1
Open on Hacker News to reply ↗

Unofficial Hacker News client; not affiliated with Y Combinator.