[Python-ideas] Partial operator (and 'third-party methods' and 'piping') [was Re: Function composition (was no subject)]

Gregory Salvan apieum at gmail.com
Sun May 10 23:23:40 CEST 2015


In my opinion, this syntax make problems when your arguments are
functions/callables.
And if you code in a functionnal paradigm it is quite common to inject
functions in arguments otherwise how would you do polymorphism ?

The only way I see to distinguish cases is to have tuples, but syntax is
quite strange.

instead of : arg->eggs(b)->spam(c)
my_partial = (arg, b)->eggs->(c, )->spam

Then how would you call my_partial ?
For example, if you have:
def eggs(a, b, c)...
def spam(d, e)...

my_partial(c, e) or my_partial(c)(e) ?



2015-05-10 22:06 GMT+02:00 Koos Zevenhoven <koos.zevenhoven at aalto.fi>:

> Reading the recent emails in the function composition thread started by
> Ivan, I realized that my below sketch for a composition operator would be
> better if it did not actually do function composition ;). Instead, -> would
> be quite powerful as 'just' a partial operator -- perhaps even more
> powerful, as I demonstrate below. However, this is not an argument against
> @ composition, which might in fact play together with this quite nicely.
>
> This allows some nice things with multi-argument functions too.
>
> I realize that it may be unlikely that a new operator would be added, but
> here it is anyway, as food for thought.  (With an existing operator, I
> suspect it would be even less likely, because of precedence rules : )
>
> So, -> would be an operator with a precedence similar to .attribute access
> (but lower than .attribute):
>
>  # The simple definition of what it does:
>  arg->func   # equivalent to functools.partial(func, arg)
>
> This would allow for instance:
>  arg -> spam() -> cheese(kind = 'gouda') -> eggs()
>
> which would be equivalent to eggs(cheese(spam(arg), kind = 'gouda'))
>
> Or even together together with the proposed @ composition:
>  rms = root @ mean @ square->map     # for an iterable non-numpy argument
>
> And here's something I find quite interesting. Together with
> @singledispatch from 3.4 (or possibly an enhanced version using type
> annotations in the future?), one could add 'third-party methods' to classes
> in other libraries without monkey patching. A dummy example:
>
> from numpy import array
> my_list = [1,2,3]
> my_array = array(my_list)
> my_mean = my_array.mean()  # This currently works in numpy
>
> from rmslib import rms
> my_rms = my_array->rms()  # efficient rms for numpy arrays
> my_other_rms = my_list->rms()  # rms that works on any iterable
>
> One would be able to distinguish between calls to methods and 'third-party
> methods' based on whether . or -> is used for accessing them, which I think
> is a good thing. Also, third-party methods would be less likely to mutate
> the object, just like func(obj) is less likely to mutate obj than
> obj.method().
>
> See more examples below. I converted my examples from last night to this
> IMO better version, because at least some of them would still be relevant.
>
> On 10.5.2015 2:07, Koos Zevenhoven wrote:
>
>> On 10.5.2015 1:03, Gregory Salvan wrote:
>>
>>> Nobody convinced by arrow operator ?
>>>
>>> like: arg -> spam -> eggs -> cheese
>>> or cheese <- eggs <- spam <- arg
>>>
>>>
>>>
>> I like | a lot because of the pipe analogy. However, having a new
>> operator for this could solve some issues about operator precedence.
>>
>> Today, I sketched one possible version that would use a new .. operator.
>> I'll explain what it would do (but with your -> instead of my ..)
>>
>> Here, the operator (.. or ->) would have a higher precedence than
>> function calls () but a lower precedence than attribute access (obj.attr).
>>
>> First, with single-argument functions spam, eggs and cheese, and a
>> non-function arg:
>>
>> arg->eggs->spam->cheese()   # equivalent to cheese(spam(eggs(arg)))
>>
>
> With -> as a partial operator, this would instead be:
>
> arg->eggs()->spam()->cheese()     # equivalent to cheese(spam(eggs(arg)))
>
>  eggs->spam->cheese  # equivalent to lambda arg: cheese(spam(eggs(arg)))
>>
>>
> With -> as a partial operator this could be:
>
> lambda arg: arg->eggs()->spam()->cheese()
>
>
>  Then, if spam and eggs both took two arguments; eggs(arg1, arg2),
>> spam(arg1, arg2)
>>
>> arg->eggs   # equivalent to partial(eggs, arg)
>> eggs->spam(a, b, c)   # equivalent to spam(eggs(a, b), c)
>>
>
> With -> as a partial operator, the first one would work, and the second
> would become:
>
> eggs(a,b)->spam(c)     # equivalent to spam(eggs(a, b), c)
>
>  arg->eggs->spam(b,c)    # equivalent to spam(eggs(arg, b), c)
>>
>>
> This would become:
>
> arg->eggs(b)->spam(c)     # equivalent to spam(eggs(arg, b), c)
>
> Note that this would be quite flexible in partial 'piping' of
> multi-argument functions.
>
>  So you could think of -> as an extended partial operator. And this would
>> naturally generalize to functions with even more arguments. The arguments
>> would always be fed in the same order as in the equivalent function call,
>> which makes for a nice rule of thumb. However, I suppose one would usually
>> avoid combinations that are difficult to understand.
>>
>> Some examples that this would enable:
>>
>>  # Example 1
>>  from numpy import square, mean, sqrt
>>  rms = square->mean->sqrt  # I think this order is fine because it is not
>> @
>>
>>
> This would become:
>
> def rms(arr):
>     return arr->square()->mean()->sqrt()
>
>   # Example 2 (both are equivalent)
>>  spam(args)->eggs->cheese() # the shell-syntax analogy that Steven
>> mentioned.
>>
>>
> This would be:
>
> spam(args)->eggs()->cheese()
>
> Of course the shell piping analogy would be quite far, because it looks so
> different.
>
>   # Example 3
>>  # Last but not least, we would finally have this :)
>>  some_sequence->len()
>>  some_object->isinstance(MyType)
>>
>>
> And:
>
>  func->map(seq)
>  func->reduce(seq)
>
> -- Koos
>
>
>
>
>
> _______________________________________________
> Python-ideas mailing list
> Python-ideas at python.org
> https://mail.python.org/mailman/listinfo/python-ideas
> Code of Conduct: http://python.org/psf/codeofconduct/
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/python-ideas/attachments/20150510/2da3664a/attachment.html>


More information about the Python-ideas mailing list