
I've looked up this feature in haskell. Dollar sign operator is used to avoid parentheses. Rationalle: Python tends to use functions instead of methods ( e.g. len([1,2,3]) instead of [1,2,3].len() ). Sometimes the expression inside parentheses may become big and using a lot of parentheses may tend to bad readability. I suggest the following syntax: len $ [1,2,3] Functions map be also chained: len $ list $ map(...) This operator may be used for function composition too: foo = len $ set $ in the same as foo = lambda *as,**kas : len(set(*as, **kas)) in current syntax Regards, Yan

Why not a functional syntax, i.e. compose(f, g, h) rather than f $ g $ h Advantage: you can do it today. Without need to convince Guido to add more line noise to the language. https://gist.github.com/stephanh42/6c9158c2470832a675fad7658048be9d Stephan 2017-10-26 13:06 GMT+02:00 Yan Pas <yanp.bugz@gmail.com>:

On 26/10/17 12:06, Yan Pas wrote:
I've looked up this feature in haskell. Dollar sign operator is used to avoid parentheses.
If I understand your example correctly, it does no such thing. "A $ B" appears to mean "apply callable A to object B", at least the way you portray it below. I don't speak Haskell so I can't comment on the original.
If you have that sort of legibility problem, it suggests that you are trying to do far too much on a single line. New syntax won't help with that (in fact it will make it worse IMHO).
I suggest the following syntax:
len $ [1,2,3]
How is this better or easier to read than "len([1,2,3])" ? What do you do for functions with two or more arguments? The obvious thing would be to make the right-hand side of the $ operator a tuple, and whoops, there are your parentheses again. I don't think this proposal achieves your aim, and I dislike it for a lot of other reasons. -- Rhodri James *-* Kynesim Ltd

On 2017-10-26 13:06, Yan Pas wrote:
I see absolutely no benefit adding this syntax when we already have a perfectly good function calling syntax.
Functions map be also chained:
len $ list $ map(...)
Function composition has been discussed at length in the past, e.g. https://mail.python.org/pipermail/python-ideas/2015-May/thread.html#33287 I'd like to highlight one key message: https://mail.python.org/pipermail/python-ideas/2015-May/033491.html Guido van Rossum wrote (May 11, 2015):
That old python-ideas thread could be of interest to you. Best Thomas

Expanding on the comments of the OP (to give more information, not necessarily to support or be against it): The "$" operator in Haskell is not a composition operator, it's essentially the same as python's apply builtin (the python2 builtin, removed for python 3), but with an operator syntax; the main trick behind it is that it's right associative, so you get that: len $ set $ str $ foo => len $ (set $ (str $ foo)) -> len(set(str(foo))) It looks a bit funky, and it works only reasonably with single-argument functions (which in haskell doesn't matter given that it uses currying that makes all function one argument functions with partial application). The best way to think about it for non Haskellers is that it's exactly like the "|" operators un UNIX-like shells, but with the reverse order; in UNIX, run foo, filter the output through str, then set, then len would read like: foo | str | set | len, which is the same as above but right to left. This is to clarify that this si NOT about function composition, just an alternate application syntax The second part of the example in the post, where composition is discussed actually relies in a completely orthogonal feature of Haskell that allows to define partial operator applications as functions, for example you can define: half = (/ 2) -- same as lambda x: x/2, so half 4 => 2 next = (+ 1) -- same as lambda x: x + 1, so next 7 => 8 invert = (1 /) -- same as lambda x: 1 / x, so invert 4 => 0.25 So this implies a new way of writing anonymous functions besides lambdas. To make the second part of the proposal work, both features should be present Now going into the discussion itself, the second feature is much more invasive on the syntax+implementation (and also backwards comptibility, given that stuff like "(+ 1)" already mean something different in python). The first feature by itself shouldn't break stuff, and even if different to what we're used to is not very unidiomatic (it leads to cleaner code, although its meaning is definitely not very discoverable). To get a rough idea on how that could work, take a look at https://gist.github.com/dmoisset/bd43b8c0ce26c9cff0ad297b7e1ba5f9 ; I just used python ** operator because that's the only right associative one. Something similar provided in the default function type (and at a low level) could work. I'd probably would like to see some code samples where this is applied to check that it's worth the trouble. D. On 26 October 2017 at 12:06, Yan Pas <yanp.bugz@gmail.com> wrote:
-- Daniel F. Moisset - UK Country Manager - Machinalis Limited www.machinalis.co.uk <http://www.machinalis.com> Skype: @dmoisset T: + 44 7398 827139 1 Fore St, London, EC2Y 9DT Machinalis Limited is a company registered in England and Wales. Registered number: 10574987.

On 26 October 2017 at 13:53, Daniel Moisset <dmoisset@machinalis.com> wrote:
This is to clarify that this si NOT about function composition, just an alternate application syntax
The idea is already dead, based on the quote from Guido, but this makes it even more clear that it's inappropriate for Python. As you said (in part that I trimmed) Haskell uses single-argument functions plus currying to implement function calls. This is extremely common for functional languages, as it matches the theoretical basis much better. As you point out, the shell pipeline model is actually quite similar (a single input, chain of processing model). Procedural languages, and Python in particular, simply don't work like that. Functions have arbitrary numbers of arguments, currying is not built in, composition is not a fundamental operation in the same way. Although it's possible to explain how a `$` style syntax would work, it doesn't fit naturally into the language - certainly not naturally enough to warrant being part of the language syntax. Paul

On Thu, Oct 26, 2017 at 6:32 AM, Paul Moore <p.f.moore@gmail.com> wrote:
Procedural languages, and Python in particular, simply don't work like that. Functions have arbitrary numbers of arguments,
And can return an arbitrary number of values. OK, technically a single tuple of values, but that does complicate the whole simple chaining thing. In short -- Python is not a functional language, even though is supports a number of functional idioms. -CHB -- Christopher Barker, Ph.D. Oceanographer Emergency Response Division NOAA/NOS/OR&R (206) 526-6959 voice 7600 Sand Point Way NE (206) 526-6329 fax Seattle, WA 98115 (206) 526-6317 main reception Chris.Barker@noaa.gov

On 27 October 2017 at 02:23, Chris Barker <chris.barker@noaa.gov> wrote:
https://bugs.python.org/issue1506122 has a brief discussion of the non-syntactic variant of this proposal: functools.compose(len, set, str)(foo) => -> len(set(str(foo))) The main concerns that resulted in the suggestion being rejected are: * it isn't clear to folks that aren't already familiar with FP why the call order for the composed functions should be right to left * it isn't clear why every function other than the rightmost one must accept a single positional arg * it isn't clear why every function other than the leftmost one must return a single result And it doesn't make sense to provide something more general, because if you're writing genuinely functional code, you do tend to abide by those restrictions. So given that our position is "We don't even want to add this to the standard library, because the learning curve for using it successfully is too steep", it's even less likely we'd be willing to add syntax for the operation. By contrast, "FP-for-Python" libraries like toolz [1] can make familiarity with those kinds of concepts and a willingness to abide by the related conventions a pre-requisite for using them. It's just opt-in, the same way that learning to define your own classes (rather than importing existing ones defined elsewhere) is opt-in. Cheers, Nick. [1] https://toolz.readthedocs.io/en/latest/ -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia

This already exists in Coconut: http://coconut.readthedocs.io/en/master/HELP.html#function-composition
Mike Am 26.10.17 um 13:06 schrieb Yan Pas:

On Fri, Oct 27, 2017 at 8:46 AM, Mike Müller <mmueller@python-academy.de> wrote:
This already exists in Coconut: http://coconut.readthedocs.io/en/master/HELP.html#function-composition
Quite funny to read that. It seems like they have made something like what I proposed in the 2015 function composition threads, but without what I considered improvements to it. I summarize the proposal below, but here's also a link to it: https://mail.python.org/pipermail/python-ideas/2015-May/033482.html Indeed, a discussion was going on where many people were interested in function composition syntax. Different variants had been proposed, and IMO one of the most notable suggestions had been using the new matrix multiplication operator. For example: from numpy import sqrt, mean, square rms = sqrt @ mean @ square rms(values) # == sqrt(mean(square(values))) And this can of course already be implemented for custom callables which implement __matmul__. But my email (linked above, and which might be a bit hard to read because of the interleaved references to my previous proposal) was essentially about something like this: Assuming bar is a function that accepts at least one argument, make foo..bar equivalent to types.MethodType(bar, foo). In other words, it would create a bound method out of bar, with foo as self. Not only would it allow calling a method which is not defined within the class: values..square() but it would also directly allow this: values..square()..mean(axis=2)..sqrt() And even when the left-hand expression becomes the second argument for a function/method: car_door..car_key.turn() # equivalent to CarKey.turn(car_key, car_door) -- Koos PS. As you can see in the email linked above, I was already prepared to just abandon the idea, because most likely it would be rejected. But what I was not prepared for was the amount of *nonsense* arguments that were thrown against it in that thread and elsewhere, and the whole thing got turned into some kind of weird puzzle.
-- + Koos Zevenhoven + http://twitter.com/k7hoven +

Why not a functional syntax, i.e. compose(f, g, h) rather than f $ g $ h Advantage: you can do it today. Without need to convince Guido to add more line noise to the language. https://gist.github.com/stephanh42/6c9158c2470832a675fad7658048be9d Stephan 2017-10-26 13:06 GMT+02:00 Yan Pas <yanp.bugz@gmail.com>:

On 26/10/17 12:06, Yan Pas wrote:
I've looked up this feature in haskell. Dollar sign operator is used to avoid parentheses.
If I understand your example correctly, it does no such thing. "A $ B" appears to mean "apply callable A to object B", at least the way you portray it below. I don't speak Haskell so I can't comment on the original.
If you have that sort of legibility problem, it suggests that you are trying to do far too much on a single line. New syntax won't help with that (in fact it will make it worse IMHO).
I suggest the following syntax:
len $ [1,2,3]
How is this better or easier to read than "len([1,2,3])" ? What do you do for functions with two or more arguments? The obvious thing would be to make the right-hand side of the $ operator a tuple, and whoops, there are your parentheses again. I don't think this proposal achieves your aim, and I dislike it for a lot of other reasons. -- Rhodri James *-* Kynesim Ltd

On 2017-10-26 13:06, Yan Pas wrote:
I see absolutely no benefit adding this syntax when we already have a perfectly good function calling syntax.
Functions map be also chained:
len $ list $ map(...)
Function composition has been discussed at length in the past, e.g. https://mail.python.org/pipermail/python-ideas/2015-May/thread.html#33287 I'd like to highlight one key message: https://mail.python.org/pipermail/python-ideas/2015-May/033491.html Guido van Rossum wrote (May 11, 2015):
That old python-ideas thread could be of interest to you. Best Thomas

Expanding on the comments of the OP (to give more information, not necessarily to support or be against it): The "$" operator in Haskell is not a composition operator, it's essentially the same as python's apply builtin (the python2 builtin, removed for python 3), but with an operator syntax; the main trick behind it is that it's right associative, so you get that: len $ set $ str $ foo => len $ (set $ (str $ foo)) -> len(set(str(foo))) It looks a bit funky, and it works only reasonably with single-argument functions (which in haskell doesn't matter given that it uses currying that makes all function one argument functions with partial application). The best way to think about it for non Haskellers is that it's exactly like the "|" operators un UNIX-like shells, but with the reverse order; in UNIX, run foo, filter the output through str, then set, then len would read like: foo | str | set | len, which is the same as above but right to left. This is to clarify that this si NOT about function composition, just an alternate application syntax The second part of the example in the post, where composition is discussed actually relies in a completely orthogonal feature of Haskell that allows to define partial operator applications as functions, for example you can define: half = (/ 2) -- same as lambda x: x/2, so half 4 => 2 next = (+ 1) -- same as lambda x: x + 1, so next 7 => 8 invert = (1 /) -- same as lambda x: 1 / x, so invert 4 => 0.25 So this implies a new way of writing anonymous functions besides lambdas. To make the second part of the proposal work, both features should be present Now going into the discussion itself, the second feature is much more invasive on the syntax+implementation (and also backwards comptibility, given that stuff like "(+ 1)" already mean something different in python). The first feature by itself shouldn't break stuff, and even if different to what we're used to is not very unidiomatic (it leads to cleaner code, although its meaning is definitely not very discoverable). To get a rough idea on how that could work, take a look at https://gist.github.com/dmoisset/bd43b8c0ce26c9cff0ad297b7e1ba5f9 ; I just used python ** operator because that's the only right associative one. Something similar provided in the default function type (and at a low level) could work. I'd probably would like to see some code samples where this is applied to check that it's worth the trouble. D. On 26 October 2017 at 12:06, Yan Pas <yanp.bugz@gmail.com> wrote:
-- Daniel F. Moisset - UK Country Manager - Machinalis Limited www.machinalis.co.uk <http://www.machinalis.com> Skype: @dmoisset T: + 44 7398 827139 1 Fore St, London, EC2Y 9DT Machinalis Limited is a company registered in England and Wales. Registered number: 10574987.

On 26 October 2017 at 13:53, Daniel Moisset <dmoisset@machinalis.com> wrote:
This is to clarify that this si NOT about function composition, just an alternate application syntax
The idea is already dead, based on the quote from Guido, but this makes it even more clear that it's inappropriate for Python. As you said (in part that I trimmed) Haskell uses single-argument functions plus currying to implement function calls. This is extremely common for functional languages, as it matches the theoretical basis much better. As you point out, the shell pipeline model is actually quite similar (a single input, chain of processing model). Procedural languages, and Python in particular, simply don't work like that. Functions have arbitrary numbers of arguments, currying is not built in, composition is not a fundamental operation in the same way. Although it's possible to explain how a `$` style syntax would work, it doesn't fit naturally into the language - certainly not naturally enough to warrant being part of the language syntax. Paul

On Thu, Oct 26, 2017 at 6:32 AM, Paul Moore <p.f.moore@gmail.com> wrote:
Procedural languages, and Python in particular, simply don't work like that. Functions have arbitrary numbers of arguments,
And can return an arbitrary number of values. OK, technically a single tuple of values, but that does complicate the whole simple chaining thing. In short -- Python is not a functional language, even though is supports a number of functional idioms. -CHB -- Christopher Barker, Ph.D. Oceanographer Emergency Response Division NOAA/NOS/OR&R (206) 526-6959 voice 7600 Sand Point Way NE (206) 526-6329 fax Seattle, WA 98115 (206) 526-6317 main reception Chris.Barker@noaa.gov

On 27 October 2017 at 02:23, Chris Barker <chris.barker@noaa.gov> wrote:
https://bugs.python.org/issue1506122 has a brief discussion of the non-syntactic variant of this proposal: functools.compose(len, set, str)(foo) => -> len(set(str(foo))) The main concerns that resulted in the suggestion being rejected are: * it isn't clear to folks that aren't already familiar with FP why the call order for the composed functions should be right to left * it isn't clear why every function other than the rightmost one must accept a single positional arg * it isn't clear why every function other than the leftmost one must return a single result And it doesn't make sense to provide something more general, because if you're writing genuinely functional code, you do tend to abide by those restrictions. So given that our position is "We don't even want to add this to the standard library, because the learning curve for using it successfully is too steep", it's even less likely we'd be willing to add syntax for the operation. By contrast, "FP-for-Python" libraries like toolz [1] can make familiarity with those kinds of concepts and a willingness to abide by the related conventions a pre-requisite for using them. It's just opt-in, the same way that learning to define your own classes (rather than importing existing ones defined elsewhere) is opt-in. Cheers, Nick. [1] https://toolz.readthedocs.io/en/latest/ -- Nick Coghlan | ncoghlan@gmail.com | Brisbane, Australia

This already exists in Coconut: http://coconut.readthedocs.io/en/master/HELP.html#function-composition
Mike Am 26.10.17 um 13:06 schrieb Yan Pas:

On Fri, Oct 27, 2017 at 8:46 AM, Mike Müller <mmueller@python-academy.de> wrote:
This already exists in Coconut: http://coconut.readthedocs.io/en/master/HELP.html#function-composition
Quite funny to read that. It seems like they have made something like what I proposed in the 2015 function composition threads, but without what I considered improvements to it. I summarize the proposal below, but here's also a link to it: https://mail.python.org/pipermail/python-ideas/2015-May/033482.html Indeed, a discussion was going on where many people were interested in function composition syntax. Different variants had been proposed, and IMO one of the most notable suggestions had been using the new matrix multiplication operator. For example: from numpy import sqrt, mean, square rms = sqrt @ mean @ square rms(values) # == sqrt(mean(square(values))) And this can of course already be implemented for custom callables which implement __matmul__. But my email (linked above, and which might be a bit hard to read because of the interleaved references to my previous proposal) was essentially about something like this: Assuming bar is a function that accepts at least one argument, make foo..bar equivalent to types.MethodType(bar, foo). In other words, it would create a bound method out of bar, with foo as self. Not only would it allow calling a method which is not defined within the class: values..square() but it would also directly allow this: values..square()..mean(axis=2)..sqrt() And even when the left-hand expression becomes the second argument for a function/method: car_door..car_key.turn() # equivalent to CarKey.turn(car_key, car_door) -- Koos PS. As you can see in the email linked above, I was already prepared to just abandon the idea, because most likely it would be rejected. But what I was not prepared for was the amount of *nonsense* arguments that were thrown against it in that thread and elsewhere, and the whole thing got turned into some kind of weird puzzle.
-- + Koos Zevenhoven + http://twitter.com/k7hoven +
participants (10)
-
Chris Barker
-
Daniel Moisset
-
Koos Zevenhoven
-
Mike Müller
-
Nick Coghlan
-
Paul Moore
-
Rhodri James
-
Stephan Houben
-
Thomas Jollans
-
Yan Pas