I’ve never been able to remember whether (f@g)(x) means f(g(x)) or g(f(x)).
That pretty much kills the idea for me.

On Sun, May 24, 2020 at 11:10 Alex Hall <alex.moj...@gmail.com> wrote:

> 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/
>
-- 
--Guido (mobile)
_______________________________________________
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/6TDH6PH2R5U4CM4QDMSLOGORT73F6BNC/
Code of Conduct: http://python.org/psf/codeofconduct/

Reply via email to