On Sun, May 24, 2020 at 6:56 PM David Mertz <me...@gnosis.cx> wrote: > On Sun, May 24, 2020 at 11:21 AM Steven D'Aprano <st...@pearwood.info> > wrote: > >> > But how would you go about getting a .__matmul__ attribute onto all >> > functions. For ones you write yourselves, you could decorate them at >> > definition. What about all the other functions though. >> >> As a functional programming fan, you might not know about this, but we >> object oriented programming people have this concept called >> "inheritance" where we would add the attribute to FunctionType once, and >> just like magic every function would support it! >> > > I think I heard of that inheritance thing somewhere! :-) > > My thought is really that there's no way we're going to get .__matmul__ > added (with the meaning "compose") to FunctionType. So I was thinking > about what one could do with a separate module. I.e. something that could > live on PyPI... before, perhaps someday, being added to standard library. > > Is there an evil way to monkey patch FunctionType? I.e. without actually > recompiling a fork of the interpreter. Alex' forbiddenfruit.curse is > pretty cool looking. But it does require explicitly cursing each > individual function that might be composed. >
forbiddenfruit patches the type, look again. I used a loop because there isn't just one FunctionType: `type(compose) != type(len)`. > Alex Hall: > >> But seriously, I don't see that much point to this idea. It's just >> slightly more concise while not being particularly readable or beginner >> friendly. >> >> sorted(paths, key=len @ str) >> sorted(paths, key=lambda p: len(str(p))) >> > > I think once you compose three or more functions, lambda starts to look > pretty bad. > It does? How? It sounds like the problem isn't the syntax for lambda, but just function composition in general, maybe because of too many parentheses. Maybe you'd like to change: foo = bar(len(str(path))) into foo = (bar @ len @ str)(path) In any case, it's rare to be able to simply compose three unary functions, e.g. `sorted(paths, key=bar @ len @ str)`. Usually you need to do something slightly more complicated, e.g. a second argument somewhere, and if you throw in functools.partial I think that's easily worse. > This is only slightly mitigated by one of those proposals for "a more > concise lambda" that occur intermittently. And if you actually save a > composed function under a meaningful name for later use, that much more so. > Why is: my_op = bar @ len @ str even more of an improvement over: my_op = lambda p: bar(len(str(p))) than @ is an improvement in the previous examples? If the answer is that you're not supposed to assign lambdas, I think the same logic should dictate not assigning compositions. In fact, the reason to not assign lambdas is for better tracebacks, and now that I think of it, function composition would completely destroy tracebacks. For example: ``` for function in [ lambda p: str(len(p)), str @ len, ]: try: function(3) except: traceback.print_exc() ``` Output: ``` Traceback (most recent call last): File "main.py", line 15, in <module> function(3) File "main.py", line 11, in <lambda> lambda p: str(len(p)), TypeError: object of type 'int' has no len() Traceback (most recent call last): File "main.py", line 15, in <module> function(3) File "main.py", line 5, in <lambda> return lambda *args, **kwargs: self(other(*args, **kwargs)) TypeError: object of type 'int' has no len() ``` https://repl.it/@alexmojaki/LeanEnergeticPublisher-1 So based on that I'm strongly against this kind of proposal without syntactic support. I've been playing more lately with R Tidyverse. It's pipe with currying of > first argument is actually really nice. The pipe operator is god-awful > ugly. But other than that it works nicely. For example: > > iris %>% group_by(Species) %>% summarize_if(is.numeric, mean) %>% > ungroup() %>% gather(measure, value, -Species) %>% arrange(value) > > > It's not abstract composition since it always starts with a concrete > object the several operations work on. But it is some of the same feel. > https://github.com/0101/pipetools
_______________________________________________ Python-ideas mailing list -- python-ideas@python.org To unsubscribe send an email to python-ideas-le...@python.org https://mail.python.org/mailman3/lists/python-ideas.python.org/ Message archived at https://mail.python.org/archives/list/python-ideas@python.org/message/JURJ5YTZ2ESEBVZYNNJ4RDSCEMH5RPB3/ Code of Conduct: http://python.org/psf/codeofconduct/