+ 15

functional programming vs pthonic list comprehension

I see filter and map covered by list comprehension: [f(i) for i in list] [i for i in list if f(i)] But how about reduce ? there a pythonic way?

2nd May 2020, 9:02 AM
Oma Falk
Oma Falk - avatar
22 Respostas
+ 10
Tibor Santa dont even think about deletingšŸ˜”šŸ˜”šŸ˜˜
2nd May 2020, 4:15 PM
Oma Falk
Oma Falk - avatar
+ 8
Very cool :D There's something interesting to be said about reducing into a list: As we know reduce takes a binary operation that makes two values into one and then does it over and over again until the list is reduced to a single value. Reducing by `a+b` obviously takes a list of numbers and sums it. But also, after we reduce, we don't know which numbers went into the final sum and in that sense we lose information! Reducing by `a.append(b)` literally just chucks all the numbers into a list and all the information about what elements came in is preserved which makes reducing into a list special :) Because of this we even give lists a special name, it's the "free monoid". And a monoid is just a type and a binary operation like we had it above. (int, a+b) is a monoid, so is (int, a*b), and (string, a+b), and the free monoid (List<Foo>, a.concat(b))
2nd May 2020, 2:17 PM
Schindlabua
Schindlabua - avatar
+ 7
Schindlabua I see you like functional programming. Do you work professionally with it? Is anyone using it professionally, in large scale? Besides ā€œpurenessā€ of leaving no temp variable behind, is there any other advantage? In python the classic for next while if else usually wins timing contest against fp. And in my view code is way more difficult to read and maintain. Am I wrong?
2nd May 2020, 6:21 PM
Edward
Edward - avatar
+ 6
or zip, or lambda, or... I donā€™t think functional programming can be replaced completely by list comprehension. Even not liking functional programming :P
2nd May 2020, 9:48 AM
Edward
Edward - avatar
+ 6
Schindlabua actually you can make reduce return a list too, although it is not the typical usage :) https://code.sololearn.com/cgU9nid0Cf1a/?ref=app But it is very different from a list comprehension either way.
2nd May 2020, 1:28 PM
Tibor Santa
Tibor Santa - avatar
+ 6
Oma Falk I could think of something like this, to use list comprehension to emulate a reduction. https://code.sololearn.com/cOxfdsJ2fEf4/?ref=app But it is really ugly and unpythonic, I don't even want to make it public. My hand itches for the Delete button. Maybe I can figure out something more functional later :)
2nd May 2020, 3:20 PM
Tibor Santa
Tibor Santa - avatar
+ 6
Schindlabua Tks for the detailed answer. Oma Falk sorry for hijacking your thread.
3rd May 2020, 6:30 AM
Edward
Edward - avatar
+ 6
Edward nono...very interesting aspects
3rd May 2020, 6:32 AM
Oma Falk
Oma Falk - avatar
+ 5
Schindlabua right but Guido said he doesnt like map and filter...since LiCo can do it and is more pythonic. Actually my question was based on this. I will edit.
2nd May 2020, 3:09 PM
Oma Falk
Oma Falk - avatar
+ 5
Schindlabua linear algebra for runaways? Booahh ...cool
2nd May 2020, 3:15 PM
Oma Falk
Oma Falk - avatar
+ 5
This is a tiny bit better as I store the intermittent state in instance variable, instead of global... https://code.sololearn.com/cY7wQuSpbx45/?ref=app
2nd May 2020, 4:46 PM
Tibor Santa
Tibor Santa - avatar
+ 5
Edward Just to illustrate how big of a deal pureness is: It means that pure functional code can be trivially run on multiple cores or machines because we know for sure that there is no shared state and nothing that can cause deadlocks. (hence Erlang for networking, it's code that is massively parallel) Pureness also implies that we can derive certain facts about functions only from looking at the type. Take a function `foo` that takes an arbitrary type `T` and returns another `T`. In Haskell syntax: foo :: t -> t Just by the fact that the type is generic and the fact that functions are pure, we *know* that the only possible implementation of foo is: foo x = x (That is, the function does nothing and returns what we plugged in). And in theory the compiler can know this too and produce more optimized code than a C compiler ever could by optimizing this function away entirely for example. But I hate co-opting threads and go off-topic so yall can drop me a DM if you want to know more about anything :D
3rd May 2020, 1:14 AM
Schindlabua
Schindlabua - avatar
+ 5
Schindlabua Edward Please do continue the thread, I find it very educational. Oma Falk agrees
3rd May 2020, 8:01 AM
Louis
Louis - avatar
+ 5
The most common use for reduce is to calculate the hash code of an object that has some iterable object attribute i.e: from functools import reduce from operation import xor def __hash__(self): hashes = map(hash, self._list) #1 return reduce(xor, hashes,0) #2 #1: generator with map to lazily compute the hash of each element of the list or iterable. #2: operation.xor could be a lambda function but it's more readable. Reduce is used (wrong) also for computing the sum of all the elements of a list, when we have the sum() built-in function that does exactly that but much more readable and simple. Answering your question, i would say that as map, filter, reduce return a generator the common Pythonic way to substitute these is by generator expressions, if you want to save memory and work lazily or with list compr if you want a list directly. Anyways, I would recommend both for their readability, this is what Python pretended since its begining: powerful but simple and readable at the same time.
3rd May 2020, 1:28 PM
Oriol Aranda
Oriol Aranda - avatar
+ 5
Also, the current map and filter in python3 are much superior to a List comprehension, because they are lazy. You can use them with infinite sequences. Of course you can also write a generator expression instead of list com. just by changing the brackets to parens. And have the same effect. Reduce in python is not lazy. So that is a huge drawback. I also think there is an aesthetic value and readability benefit in map and filter. For example compare: filter(bool, iterable) (n for n in iterable if n) I find the first form much easier to read, even though the effect is exactly the same. I also disagree with Guido's argument about associativity. I dipped my hand in Haskell a bit too and there we have foldr and foldl functions that are similar to reduce, and the difference between the two is the direction they process the list, starting from left or right. Associativity of the function (operator) plays a huge role there. Python reduce is really simplified compared to that.
4th May 2020, 11:28 AM
Tibor Santa
Tibor Santa - avatar
+ 4
Functional programming is more than just map/reduce, just saying :P List comprehensions can't possibly implement reduce, because reduce takes a list and returns a non-list. And list comprehensions always give you lists.
2nd May 2020, 1:00 PM
Schindlabua
Schindlabua - avatar
+ 4
Edward Love it, but I don't use it professionally no (I'm just a webdev) Facebook employs a few Haskell programmers and they use it for some friend-relationship graph theory stuff, and I hear Erlang is a popular language for programming networking hardware like switches and such. Those are the only large-scale uses I am aware of. In Haskell anyway pureness is a big selling point. Haskell's "laziness" is really cool and unique but I'd need more space to explain. In my mind Haskell is mostly for exploring functional maths and the ghc compiler is mostly for studying novel optimization techniques but people may disagree. And Haskell is only hard to read because you aren't used to it :P I find it very easy on the eyes and writing code in terms of say map/reduce instead of for loops gets the point across more quickly. I encourage everyone to try Haskell for a bit, it really expands your toolbox and will make your imperative code better aswell. I see Functors/Monads/Monoids *everywhere* now because of it!
3rd May 2020, 1:07 AM
Schindlabua
Schindlabua - avatar
+ 3
I have to respectfully disagree with Guido there. While reducing by associative operators is the simplest usecase (Haskell has it's own function for that, mconcat, concatenation in a given monoid) it's not the most common by a long stretch. That's because "associative" here implies that both sides of the operator take the same type. (Since in `(a * b) * c = a * (b * c)`, `b` appears on both sides) And that's in my experience not the way we use reduce most of the time; we usually reduce to a different type than the type of list we plugged in. Example: You write a game, it has multiple phases, in javascript I would `phases.reduce((state, phase) => phase(state), currentGameState)` to run the entire game one phase after the other. But Guido's blogpost was written in 2005, when functional code was less mainstream. Maybe he has different opinions now. Modern javascript looooves reduce.
4th May 2020, 11:09 AM
Schindlabua
Schindlabua - avatar
+ 1
just to show that reduce is complicated, I think it can't be replaced by a list comprehension https://code.sololearn.com/cfKQjla8QP21/?ref=app
3rd May 2020, 6:10 AM
Aymen