upvote
> Put me anecdotally in the opposite bucket.

The fact that you wrote this comment with Hindley-Milner-ish notation already makes your an outlier.

reply
I think part of the issue is that a lot of programming languages don't make a strong distinction between the two, and only provide the (more powerful) fold, but in a way that makes reduce operations harder to reason about (like OP said, with 0 types).

Associativity also makes fold hard. It's not super trivial to know when you might need e.g. left fold vs right fold

reply
These are pretty close to each other, to the point where I wouldn't bother strongly distinguishing them.

Suppose we have foldr as in [A] -> B -> ((A, B) -> B) -> B, foldl as in [A] -> B -> ((B, A) -> B) -> B, and reduce as in [A] -> ((A, A) -> A) -> A.

Then we have foldr list value operator = reduce [\b -> operator a b | a <- list] (.), foldl list value operator = foldr (reverse list) value (flip operator), and in the case of a finite non-empty list and associative operator, we have reduce list operator = foldr (tail list) (head list) operator = foldl (init list) (last list) operator.

So these are all basically slight re-parametrizations of each other.

reply
> `fold` is awesome and super useful. It's the easiest and most convenient way to turn a collection into a single value.

You will eventually learn about something called "for loop", and it will be nice.

reply
There are way more places where a simple typo will ruin you in a for loop than a reduce or fold or map. Using briefer abstractions in place of nested loops is almost always preferable.
reply
> Using briefer abstractions in place of nested loops is almost always preferable.

Indeed, this is why everyone knows the J programming language.

reply
Nah. It involves multiple passes and setting the answer to the wrong value before (hopefully) setting it to the right value.

Plus it forces you out of whatever lazy/streaming paradigm you had going on. If your foldr produces a list, downstream can start consuming it in constant memory as long as you let it do its thing.

reply
fold kinda does too, for setting the first combined value that you are assembling, and thus on an empty list you end up with that wrong value, same as the for loop
reply
japgolly’s signature for reduce above is slightly wrong, it should be `[A] -> ((A,A) -> A) -> Maybe A`.

I.e. there is no initial value to pass in, but the result is an Optional to handle the empty iterator case. That’s how rust does it, for example:

https://doc.rust-lang.org/std/iter/trait.Iterator.html#metho...

reply
No, the sum of the first ten natural numbers is always 55. It is not "initialised" to some other number beforehand.
reply