[HN Gopher] Toolz: A functional standard library for Python ___________________________________________________________________ Toolz: A functional standard library for Python Author : optimalsolver Score : 84 points Date : 2021-01-21 08:10 UTC (14 hours ago) (HTM) web link (github.com) (TXT) w3m dump (github.com) | lysium wrote: | I prefer functional style whenever I can. I noticed that this | style slows Python programs down. It seems function calls are | rather expensive. Does anybody have a similar experience? | vmchale wrote: | They have to check a recursion limit, for one. | AlexCoventry wrote: | It's been a while since I knew those kinds of details, but it | certainly been the case in the past. | | https://stackoverflow.com/questions/22893139/why-is-a-functi... | heavyset_go wrote: | PEP 590[1] makes calling callables less expensive. It was | finalized for Python 3.9. | | [1] https://www.python.org/dev/peps/pep-0590/ | thisiszilff wrote: | Yes, I suspect it is a pitfall of a multi-paradigm language | that cannot assume so much about code in order to optimize. | Opinionated functional languages (ie clojure, haskell) can have | a lot more guarantees about what is going on in order to | optimize all those function calls, lexical bindings, etc. | vmchale wrote: | There's a bunch of oddities in Python, e.g. recursion limits. | vorticalbox wrote: | I've been writing functional code for a year or so now at work | with the help of ramda in nodejs, there is also a port for | python. | | My colleagues don't like becuase it's so different to what they | are used to but I am putting out code faster and with less bugs | so I'm not going to stop. | archarios wrote: | Hell yeah me too! Some of my coworkers like it, but there are a | few out there who basically don't want to learn something new.. | I have been using Ramda professionally for about two years now | and I love the heck out of it. My org is using more and more | TypeScript which makes using Ramda a little harder but it still | works pretty well in this context too. I have been working on a | test data inventory project with Ramda recently and it has made | the implementation so much nicer than it would have been | otherwise. I started using pipeP (by defining it with pipeWith) | and omg it's so great for dealing with a mix of async and non | async calls. | [deleted] | zelphirkalt wrote: | Why use a library for it? Can it not be done with just Python? | And if using the library is much different from normal Python, | does it mitigate Python's problems with functional programming? | (For example one expression only lambdas and no TCO.) | | I also do use some functional concepts in my Python work, but | do not use a library for it. Only procedures or functions. No | additional dependencies. | gugagore wrote: | I think `grouby` is a compelling example: | | https://toolz.readthedocs.io/en/latest/control.html#other- | pa... | | > Most programmers have written code exactly like this over | and over again, just like they may have repeated the map | control pattern. When we identify code as a groupby operation | we mentally collapse the detailed manipulation into a single | concept. | | If you don't use a library, then you have to re-write | something like groupby many times, I would expect. Or WORSE, | you don't even use the pattern, writing "code exactly like | this over and over again". | zelphirkalt wrote: | Huh, interesting. This does not remind me of the database | groupby operation, but rather of partition, like in SRFI-1. | I mean in natural language it is clear to me, why they'd | name it groupby, but in programming terms I think partition | is more appropriate, as groupby is already "blocked" by the | database operation. | | Often one only needs one of the partitions though, which is | when filter is sufficient. Otherwise I guess one can easily | write partition oneself and then use that function over and | over again, without resorting to a library. | | But perhaps it is a good example, so that you do not have | to write partition in every project and if the additional | dependency is OK to have, why not, if it is indeed a good | one. | seertaak wrote: | Functional programming in Python is severely hampererd by | Python's lambda keyword, which - simply put - sucks. | samasblack wrote: | I like the way the Functional Programming HOWTO in the Python | docs (https://docs.python.org/3/howto/functional.html#small- | functi...) puts it: Fredrik Lundh once | suggested the following set of rules for refactoring uses of | lambda: 1. Write a lambda function. 2. Write a | comment explaining what the heck that lambda does. 3. | Study the comment for a while, and think of a name that | captures the essence of the comment. 4. Convert the | lambda to a def statement, using that name. 5. Remove the | comment. | cabalamat wrote: | Given that Python allows unicode characters in source, I'm | surprised it doesn't allow lambda to be replaced by the l | character. | JNRowe wrote: | For those, like me, who get excited by this note that there | are restrictions on the Unicode categories that are allowed, | see the supported characters1 and gory details2. It is often | enough to write math-y code in a usable way, but occasionally | you'll find you can't use the character you want. | | 1 https://docs.python.org/3/reference/lexical_analysis.html#i | d... | | 2 https://www.python.org/dev/peps/pep-3131/ | alrs wrote: | I'm surprised that you're surprised. | vmchale wrote: | Also the recursion limit. | pansa2 wrote: | And no tail-call optimization. | xapata wrote: | Intentional to improve tracebacks. There's trade-offs with | every design decision. | heavyset_go wrote: | Yeah, Python would really benefit from multi-line anonymous | functions. | | There was a limitation in Python where spacing and indentation | gets ignored between parentheses, which makes it impossible to | pass a multi-line lambda as an argument to a method or | function. However, given the new parser, that limitation might | be able to be mitigated. | pansa2 wrote: | I don't think this limitation is likely to change - the only | ways to allow whitespace-sensitive statements inside an | argument list are all really ugly. | scott_russell wrote: | Agreed. I suspect that most uses of python decorators become | moot with proper multi-line anonymous functions. I assume | some would argue that decorators create more readable code | but they seemed like a syntax hack to me. | fwip wrote: | You can do multiple lines, just not multiple statements: | >>> f = lambda x: x * \ ... 20 >>> | >>> f <function <lambda> at 0x7f8b69f2c6a8> | >>> f(2) 40 | [deleted] | pansa2 wrote: | In fact, no statements at all - just a single expression. | tutfbhuf wrote: | But you can define functions inside of functions | (recursively). def function1(): | print ("hello outer") def function2(): | print ("hello inner") function2() | function1() | | Output: hello outer hello inner | throwaway894345 wrote: | But you can't do that (or try/except) in an expression such | as a list comprehension or similar. | robertlagrant wrote: | Yes, because gross. | mumblemumble wrote: | I can't agree with this any harder. | | I've spent the past few months familiarizing myself with | a legacy codebase in a functional language. If I could | pick a single thing about the code that is just the | absolute worst stumbling block, and that has made | learning understanding the code unreasonably difficult, | it's multiline anonymous functions. In general, if the | function is doing something complex enough to need | multiple lines, it's doing something complex enough to | deserve a name. | 0x2c8 wrote: | Can you elaborate on this? What is wrong with Python's | `lambda`? | rustyminnow wrote: | Like others have said: | | - Can only have one line | | - Can only use expressions, not statements. E.g. `print`s, | loops, conditionals are out. | | - Overall just kinda clunky | | Here's an SO post about lambdas where the answer is "Use def | instead." https://stackoverflow.com/questions/14843777/how- | to-write-py... | bobbylarrybobby wrote: | The lambda calculus is Turing complete, so in theory, | Python's lambdas should suffice... | jolux wrote: | Turing completeness is completely unrelated to whether or | not anonymous functions are easy to use in Python. | rustyminnow wrote: | I mean... You're right. They suffice. They're just less | friendly (i.e. useful) than lambdas in other languages. | zelphirkalt wrote: | Which of course says nothing about usability and | readability. | heavyset_go wrote: | print() is a function now and you can use it with lambdas. | diarrhea wrote: | This works for conditionals: In [4]: f = | lambda x: "Yes" if x else "No" In [5]: f(True) | Out[5]: 'Yes' In [6]: f(False) Out[6]: | 'No' | | It's Python's version of ternary operators, so not sure if | that counts as a "true" conditional; but it is one. | | Loops don't work, but list comprehensions do, and they are | definitely the way to go here. Multi-line loops deserve a | `def`. | seertaak wrote: | Exactly. Kind of an own-goal too, from none other than ex- | BDFL. While not totally obvious, it's not impossible to | widen the syntax to allow multi-line lambdas, you just need | to ditch the stack-based lexer-integrated whitespace | sensitivity behaviour. | VWWHFSfQ wrote: | The use of lambda is becoming somewhat of a smell in Python | in general. PSF's own black code formatter will complain | about using it and pretty much always says to just use a def | instead | kissgyorgy wrote: | It can only have one line for example. | pansa2 wrote: | Python's `lambda` can only contain a single expression. | | There's no good way to add support for full anonymous | functions to Python's grammar. One of the rules that makes | significant-whitespace work elegantly is that statements can | contain expressions, but never vice-versa. | ausjke wrote: | since lambda is for simple and short anonymous functions most | of the time why do I need type the whole word each time? can | they also do what javascript does(or similar): | x => x * 2 | | instead of lambda x : x * 2 | cabalamat wrote: | I like: lx: x*2 | pansa2 wrote: | Until very recently, Python's grammar was strictly LL(1), | so the parser couldn't handle, for example, `(x, y) => x * | y`. | | Perhaps with the move to a PEG parser, this syntax could | now be supported? | AlexCoventry wrote: | Also by the lack of persistent data structures with structural | sharing. That forces you to take an expensive copy whenever you | want a modified version of some data, or bash it in place. | heavyset_go wrote: | There's Pyrsistent[1], which provides persistent data | structures. | | [1] https://github.com/tobgu/pyrsistent | Iwan-Zotow wrote: | Isn't it a true functional way? | iimblack wrote: | I could definitely be wrong but I think most functional | data structures aren't fully copied. Instead, they'll | utilize something like a pointer to the data that stayed | the same so only the part that changes is "copied". | alentist wrote: | There are smarter ways to deal with data structures in the | functional setting than copying the entire structure over | and over again. | | See https://en.wikipedia.org/wiki/Purely_functional_data_st | ructu... and Okasaki's book _Purely Functional Data | Structures_. | gameswithgo wrote: | I imagine it is problematic that Python is already very slow, | and then to pile up idioms with performance downsides on top of | that is kind of rough. | jolux wrote: | Functional programming doesn't have an inherent performance | downside, but it depends on specific optimizations in | compilers and runtimes to make it fast. Python doesn't really | optimize anything from what I know. | bj0 wrote: | This is one of the biggest reasons I really like (the python | superset) Coconut: https://github.com/evhub/coconut | refactor_master wrote: | It looks interesting, but I'm not entirely sold. All the | examples are about math functions, which is kind of stupid to | implement in Python. | | How does this benefit "plumbing"? | | My biggest problem with Python is that I either have to write | | list(function1(*function2(len(obj.method()))) | | Or try to avoid all the variables by using classes... which | is fine... if it wasn't for self taking up roughly a third of | the word count. | Grimm1 wrote: | I had a bit of a derp here at first, I was like what, python | already has a functional (as in working) standard lib, then I | read the docs and was like ohhhhh that functional. | | I think python made some half measures in regards to functional | programming, not a bad thing since python tends to blend the | different styles decently but at least for me it would be nice to | have a good library to extend the functional side a little more, | hopefully this scratches the itch. | jonmoore wrote: | Toolz, like seemingly everything Matt Rocklin is a major | contributor to, is something of a model library: cleanly designed | and coded, with strong documentation. | | Although Python is not going to match a full Lisp, Haskell or ML | in all their strengths, using a functional style can be useful | and expressive. The toolz docs give some relevant background at | https://toolz.readthedocs.io/en/latest/heritage.html . | | At a language level, Peter Norvig gave a lengthy comparison of | Python and Lisp at https://norvig.com/python-lisp.html in 2000. ___________________________________________________________________ (page generated 2021-01-21 23:01 UTC)