[Python-ideas] Function composition (was no subject)

Koos Zevenhoven koos.zevenhoven at aalto.fi
Sat May 9 21:15:21 CEST 2015


On 2015-05-09 21:16, Steven D'Aprano wrote:
> On Sat, May 09, 2015 at 11:38:38AM -0400, Ron Adam wrote:
>
>> How about an operator for partial?
>>
>>            root @ mean @ map $ square(xs)
> Apart from the little matter that Guido has said that $ will never be
> used as an operator in Python, what is the association between $ and
> partial?
>
> Most other operators have either been used for centuries e.g. + and - or
> at least decades e.g. * for multiplication because ASCII doesn't have
> the × symbol. The barrier to using a completely arbitrary symbol with no
> association to the function it plays should be considered very high.
>
> I would only support an operator for function composition if it was at
> least close to the standard operators used for function composition in
> other areas. @ at least suggests the ∘ used in mathematics, e.g.
> sin∘cos, but | is used in pipelining languages and shells and could be
> considered, e.g. ls | wc.
>
> My own preference would be to look at @ as the closest available ASCII
> symbol to ∘ and use it for left-to-right composition, and | for
> left-to-right function application. E.g.
>
> (spam @ eggs @ cheese)(arg) is equivalent to spam(eggs(cheese(arg)))
>
> (spam | eggs | cheese)(arg) is equivalent to cheese(eggs(spam(arg)))
>
> also known as compose() and rcompose().
> We can read "@" as "of", "spam of eggs of cheese of arg", and | as
> a pipe, "spam(arg) piped to eggs piped to cheese".

For me these are by far the most logical ones too, for exactly the same 
reasons (and because of the connection of @ with matrix multiplication 
and operators that operate from the left).

> It's a pity we can't match the shell syntax and write:
>
> spam(args)|eggs|cheese
>
> but that would have a completely different meaning.
>


But it does not need to have a different meaning. You could in addition 
have:

spam @ eggs @ cheese @ arg   #  equivalent to spam(eggs(cheese(arg)))

arg | spam | eggs | cheese    # equivalent to cheese(eggs(spam(arg)))

Here, arg would thus be recognized as not a function.

In this version, your example of spam(args)|eggs|cheese would do exactly 
the same operation as (spam | eggs | cheese)(args) :-).


> David Beazley has a tutorial on using coroutines in pipelines:
>
> http://www.dabeaz.com/coroutines/
>
> where he ends up writing this:
>
>      f = open("access-log")
>      follow(f,
>             grep('python',
>             printer()))
>
>
> Coroutines grep() and printer() make up the pipeline. I cannot help but
> feel that the | syntax would be especially powerful for this sort of
> data processing purpose:
>
>      # could this work using some form of function composition?
>      follow(f, grep('python')|printer)
>
>
>

This seems promising!


-- Koos



More information about the Python-ideas mailing list