Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why is using reduce with non-associative operators considered bad style?

As Guido says in his The fate of reduce() in Python 3000 post:

So now reduce(). This is actually the one I've always hated most, because, apart from a few examples involving + or *, almost every time I see a reduce() call with a non-trivial function argument, I need to grab pen and paper to diagram what's actually being fed into that function before I understand what the reduce() is supposed to do. So in my mind, the applicability of reduce() is pretty much limited to associative operators, and in all other cases it's better to write out the accumulation loop explicitly.

I'm confused by the statement:

the applicability of reduce() is pretty much limited to associative operators

Isn't reduce in python just an lfold operation (left to right)? I get that order can be non-deterministic if used with sets or dict keys -- is that the only reason?

Here is an example of a nice usage of reduce for a non-associative operation:

def pass_thru(prev, next_func):
    return next_func(prev)

def flow(seed, *funcs):
    return reduce(pass_thru, funcs, seed)

flow('HELLO',
     str.lower,
     str.capitalize,
     str.swapcase)
#returns 'hELLO'

What concerns me is if I should worry about a non-guaranteed conformance to lfold, future multi-threaded implementations or just watch out for non-deterministic iterables like sets and dict.

like image 377
Doug Coburn Avatar asked Nov 22 '25 16:11

Doug Coburn


1 Answers

While I have to say I agree with you, and I really liked the flow example you've presented,

I can see some merit to Guido's claims that reduce is not as explicit as a direct loop. And it might be confusing if you are not used to FP's higher order functions.

I think that higher order function such as map , filter and zip are very useful, they are declarative by nature, and do not define the explicit implementation.

You can use spark's map, the multiprocessing.Pool's map or the built-in map, and the return value should be the same.

However, when it comes to reduce, the implementation is serial by nature. and in fact, you do not gain any abstraction over using a direct loop.

Thus, I can see how reduce may conflict with the Zen of Python:

There should be one-- and preferably only one --obvious way to do it.

like image 77
Uri Goren Avatar answered Nov 25 '25 06:11

Uri Goren