On Apr 8, 2014, at 16:00, Michael Mitchell <epsilonmichael@gmail.com> wrote:
I'm not confident I can make that case very well, but I suppose I can try :).
There do seem to be some hand-rolled composition functions in various Github repositories: https://github.com/search?l=python&q=%22def+compose%22&ref=searchresults&type=Code
I'm not sure why a composition operator has never been added to the functools library, but I'd make the observation that a composition function wouldn't be much less verbose than in my earlier lambda example. A infix binary operator, however, would be quite more concise, especially so when chaining multiple functions.
A few problems have been raised with this. The big one is that it's not clear what it means to compose functions unless they take and return a single value. While you could make it call g(*f(x)) to pass multiple values, that makes it no longer work with single-value functions. Functional languages deal with that by having equally compact ways to do all kinds of other general higher-order tasks, like partialing functions and sectioning operators (or they just use currying to make all functions partial), flipping arguments, raising functions (like a map that returns a function over an iterable, instead of taking an iterable in the map call), etc. Python has nothing but partial, it's not that compact, and it's buried in functools. Also, some people find that code using higher-order functions more than necessary usually doesn't look very pythonic. All kinds of things that are done by building up a higher-order function and then calling it in a language like Haskell are usually instead done by chaining or imperatively calling functions in Python. This could lead to a "more than one way to do it" situation, or just to code that's harder to understand without thinking it through. (I personally don't find this argument very compelling, but then it's hard for me to put myself in the shoes of people who never use functional languages, so that may not mean much. And I think Guido is one of the people who finds it compelling.) Both left-compose and right-compose are perfectly valid operations, and the one that looks obviously right to novices is the opposite of the one that's obviously right (or at least more often) to experts. Finally, compose and matrix multiplication are false cognates. Matrices are operations on vectors under multiplication--the same operator used for composing those operations. Functions are operations on values under calling--a completely different operator than @. Finally, it would help to have a real use case instead of just filter(a @ b, x). Presumably b is some function from elements of x to some other type, and a is a predicate function from that type to bool... but it's hard to think of useful functions (as opposed to expressions you'd have to wrap in lambda anyway) that fit that bill off the top of my head. None of these means the idea is impossible or useless, just that it's less obvious a win than it looks at first.
There's also precedent to the @ symbol being associated with functions, i.e. decorator syntax. Decorators are callables that accept callables and return callables, which parallels the infix definition of accepting two callables and returning a callable.
On Tue, Apr 8, 2014 at 2:17 PM, Nathaniel Smith <njs@pobox.com> wrote:
It's been raised a few times, but the problem is that there's no evidence that anyone actually needs a short way to perform composition - notice the composition operation's never even been added to functools. If you do want to make that case though then there's nothing stopping you :-)
On 8 Apr 2014 22:10, "Michael Mitchell" <epsilonmichael@gmail.com> wrote:
I haven't been following this thread too closely, so please stop me if this has been covered, but has overloading the @ operator as function composition been considered yet?
An example would be
filter(a @ b, lst)
as opposed to
filter(lambda x: a(b(x)), lst)
On Sun, Apr 6, 2014 at 6:51 PM, Nathaniel Smith <njs@pobox.com> wrote:
On Mon, Apr 7, 2014 at 12:20 AM, Steven D'Aprano <steve@pearwood.info> wrote:
On Sun, Apr 06, 2014 at 11:02:00PM +0100, Nathaniel Smith wrote:
On Sun, Mar 16, 2014 at 1:05 PM, Nick Coghlan <ncoghlan@gmail.com> wrote: > Aye, but at the moment it makes sense to wait and see if there is even > an argument to be had - Nathaniel may decide that even after reviewing > the question seriously, he doesn't want to propose a right associative > operator :)
And indeed, that does seem to be the way things have worked out :-). http://mail.scipy.org/pipermail/numpy-discussion/2014-April/069834.html
That's a shame in one way -- for anyone using operator overloading to define their own DSL, there's only ** if you want a right-associative operator to overload. Still, that's an extremely marginal, and hypothetical, use-case. Left-associative it is.
Was that the last blocker for the PEP?
Pretty much. Just posted to python-dev: https://mail.python.org/pipermail/python-dev/2014-April/133791.html
-n
-- Nathaniel J. Smith Postdoctoral researcher - Informatics - University of Edinburgh http://vorpus.org _______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/
_______________________________________________ Python-ideas mailing list Python-ideas@python.org https://mail.python.org/mailman/listinfo/python-ideas Code of Conduct: http://python.org/psf/codeofconduct/