logoalt Hacker News

Anecdotally, programmers dislike "reduce"

151 pointsby vinhnxlast Monday at 6:46 AM234 commentsview on HN

Comments

yipinwongyesterday at 9:56 PM

Reduce introduces state (accumulator), unlike map/filter which normally are used for immutability.

I use both, but do not like reduce at all. It's harder to read, yes. But I see the point of using them all.

olivewonglast Monday at 6:51 PM

I agree, but I think a lot of it is variable name abuse on the accumulator, making it unclear. I've seen a lot of single letter or worse, a coworker who named it "cum" for short which is super not okay

patwolfyesterday at 7:16 PM

I've worked with developers that were reduce maximalist. During PR reviews, anything that could be rewritten with reduce was flagged. One of the benefits of AI is not having to care as much about things like that.

grommet_kittoday at 12:22 AM

Totally get it. `reduce` feels like a hammer for every nail; often `map` or `filter` makes intent clearer for others.

very-old-swtoday at 12:00 AM

Reduce with barriers is essential (and amazingly powerful) in parallel functional programming languages like CUDA Thrust.

show 1 reply
Bayard_netoday at 12:13 AM

Yeah, it usually adds cognitive load for anything beyond basic summation. Simpler to just use a good old `for` loop.

ChrisMarshallNYyesterday at 6:36 PM

I like it, but I don't use it anywhere near as much as other built-in closures.

I find the two ways that you call it to be a bit annoying (not a showstopper). It just seems a bit "kludgy" to me.

theamklast Monday at 5:41 PM

At least in Python, I've found that "reduce" is very rarely needed. Most of the times, "sum" is enough, sometimes with "start" values customized (set it to [] to flatten an array for example). It is both easier to read, faster, and needs no imports. It also works great with list comprehensions - "sum(foo(x) for x in input if x > 5)" is much easier to read than reduce equivalent.

If you are multiplying, you are likely doing heavy math, and you'll be using numpy - which does not need reduce either.

If you are going to return a list of dict, then it's much faster to mutate the results, so using "reduce" will have significant performance implications (unless you want to return input argument, mis-using it as a glorified "for" loop)

And if returning not a list/dict, if you can use "min" or "max" or "any" or "all" or "next" (take the first element), then you should use it - it will be easier to read and faster too.

So what does this leave us for "reduce"? Frankly, not much. I've only seen it in merging immutable status codes, and that was pretty niche usecase to begin with.

(this was all for Python. In other languages without nice list of built-ins reduce might make more sense)

show 2 replies
noriryesterday at 6:42 PM

Anywhere that I could use reduce, I instead write a tail recursive function. This is also why I do not and will not ever choose python or javascript voluntarily.

billyp-rvalast Monday at 7:37 PM

Well yeah, it's the lowest-level array function. All of the others can be written with reduce, but not vice-versa. Of course it's going to be less friendly.

eimrinelast Monday at 3:01 PM

Reduce requires knowing that the sum of zero entities is zero but the multiply of zero entities is one. They forget to throw the correct number and think that reduce() just do not work for them.

Terr_yesterday at 10:24 PM

Sure, I'm up for some bike-shedding. [0][1] Unless performance demands otherwise, I prefer map+filter because:

1. It's cheaper/faster at communicating intent to humans reading your code. Since a reduce call can do all sorts of interesting things, people need to stare harder to realize "oh, it's just doing a a map and filter together."

2. Things are easier to debug. I can vet the process of transformation (and its intermediate results) and then vet the process of excluding some of those results.

_____

With respect to debugging, a sample form Elixir's REPL where the piping (|>) to the dbg() function reveals the intermediate state:

    iex(1)> [5,34,6,2,7,3,1] |> 
                     Enum.map(fn x -> x * x end) |>
                     Enum.filter(fn x -> x < 10 end) |> 
                     dbg()

    [iex:4: (file)]
    [5, 34, 6, 2, 7, 3, 1] #=> [5, 34, 6, 2, 7, 3, 1]
    |> Enum.map(fn x -> x * x end) #=> [25, 1156, 36, 4, 49, 9, 1]
    |> Enum.filter(fn x -> x < 10 end) #=> [4, 9, 1]


[0] https://en.wikipedia.org/wiki/Law_of_triviality

[1] https://www.smbc-comics.com/comic/noun

hyperhellolast Monday at 1:37 PM

For can have another set of variables in the header too. You can simulate it more readably even if you need to call the lambda.

g8ozlast Monday at 9:09 PM

I've always like reduce myself, didn't realize others had a negative attitude towards it.

asgrtoday at 7:05 AM

reduce is great - love it.

globular-toasttoday at 6:45 AM

Most programmers aren't comfortable with higher-order functions, in my experience. Map and filter are special cases that they may have learnt, but other less common cases they don't understand.

Also, in many languages reduce is hobbled by the fact operators aren't functions. I used it Common Lisp all the time, but it's awkward to use in, say, Python as the function you want is so often an operator. It's also more beautiful if the operators are n-ary like in CL, so the result of (reduce #'+ '()) is the same as (+), ie. 0.

very-old-swyesterday at 11:59 PM

reduce with barriers is essential in parallel functional programming. See the CUDA thrust package.

pjmlptoday at 7:34 AM

Not really, programmers only educated in traditional imperative programming I would assert.

fatbirdtoday at 5:53 AM

I had a client call me up and complain about my reduce code because it was hard to read and he couldn't tell what was going on. I broke through to him when I added comments to it that showed a particular data structure going in, and what was coming out. Once the transformation was clear, the apparent complexity was no longer a problem, leaving me to believe that the problem with reduce is almost entirely about legibility.

mahboiyesterday at 10:21 PM

Reduce always makes me question the performance and order of operations. The most I'll do in Python is like

  sum(x[1] for x in args)
which is map + reduce. And that's only if x[1] is a number. That's about it. No equivalent in JS. Whenever some JS code has map, I'm like why, and rewrite it as a loop.

This is also assuming we're talking about regular code and not an actual map-reduce framework like Spark.

WesolyKubeczekyesterday at 6:46 PM

I like neither of the three and prefer for loops and if statements instead. Yay for shallower stacks!

scotty79yesterday at 10:11 PM

Alternative theory - reduce is badly named.

combine, accumulate it aggregate would have way more use.

mcphageyesterday at 7:39 PM

I like it, but don't care for the name. I find it easier to think about in terms of an accumulator.

jan_m_savagetoday at 1:18 AM

[dead]

fatih-erikli-cgyesterday at 9:52 PM

[dead]

semiinfinitelyyesterday at 6:30 PM

you guys still reading and review code with ur eyes and brain?

show 1 reply