Overloading operators for currying, a PEP309 suggestion

Lenard Lindstrom PEP308reply at telus.net
Thu Mar 13 00:11:46 EST 2003


"Stephen Horne" <intentionally at blank.co.uk> wrote in message
news:0b2u6vcq3o6bu1rkd3sc2htqgi9n7k955h at 4ax.com...
> On Wed, 12 Mar 2003 07:08:01 GMT, "Lenard Lindstrom"
> <PEP308reply at telus.net> wrote:
>...
> >Using my '<<' grammer, positional assignment might be done like this:
> >
> >fn << {<posn>:<value>, ...}
> >
> >eg:
> >    fn1 = fn << {1:'a'}  # the key is an integer posn rather than an arg.
> >name.
>
> I think this creates a problem.
>
>   fn << 1              #  Curries left parameter with rvalue
>   fn << { 2 : "x" }    #  Does not curry left parameter with rvalue -
>                        #  treats rvalues type as special case.
>
It does create a problem.

    fn | {<posn>:<value, ...}

is consistant with my suggested syntax. Maybe my mistake shows that my
operator choices are confusing. Actually, my biggest concern is with the
precedence of the '<<' operator. An expression to the right the '<<' must be
parenthesized if in has bitwise or comparison operators. Yet in a function
call argument list only tuples need parentheses. This is confusing.

eg.

   def fn(doprint, value):    # Takes a boolean argument
        if doprint: print 'value =', value
   x = 5
   fn(x < 10, x)                     # Works just fine
   fn1 = fn << x < 10 << x    # Should this work?
   fn1()                                # fails because 'bool' object not
callable
   fn1 = fn << (x < 10) << x  # parentheses required.
   fn1()                                # Now it works.

Unfortunately, every overloadable operation with precedence lower than '|'
has special behaviour.

>...
> >Maybe this is where __call__ comes in.
> >    <closure-item-ref>(<value>, ...)
>
> Not sure - call syntax suggests calling to strongly, which we are not
> doing. I though it would be better to choose a syntax which emphasizes
> that no call is done - only manipulation of closure contents and
> selection flags.
>
I intended the syntax to resemble a call. The idea behind currying is to
break down a function call into a series of single argument calls. I like
the __getitem__ approach with __call__ because now the implied calls are
obvious.

However, you are right in that what I suggest is not currying in the purest
sense.

for:
    quad = lambda a, b, c, x: x(a*x + b) * c

    result = quad << 1 << 2 << 3 << 2         # My syntax
or
    result = quad[0:3] << (1, 2, 3, 2)            # Your syntax
or
    result = quad[0:3](1,2,3,2)

'result' is not 11 as it would be for currying, but a function object taking
no arguments. This allows for side effects. So which is preferable,
operators that emphasize the connection to actual currying or operators that
warn the programmer that this is something different? I am unsure on this.
My variation on 'currying' comes from PEP 309 and related postings.

>...
> > Anyways, implementing value
> >retrieval would require additional data be kept around if Python closures
> >are used to save the argument values.
>
> I didn't know that - I don't know how Python closures work, only what
> the general principle behind closures is.
>
> > How important is it?
>
> Not important - which is why an awkward syntax didn't seem to be a
> problem.
>
Actually allowing for argument value retrieval may not be such a big
problem. Keeping extra data around would only slow the currying operators.
The resulting functions would be just as fast. Anyway, there could always be
two curry classes, a bare-bones performance version as well as a full
featured version.

>...
> >from functional import curryfunction
> >
> >def fn(<args>):
> >    <body>
> >fn = curryfunction(fn)
>
> Yes, but - erm - well - I don't like it!
>
> I don't think you should need to convert a normal function into a
> curryable function - functions should be functions, whether they
> support currying or not.
>
I don't like it either. This is the simplest way without requiring changes
to the language.


An aside:
For anyone interested, the three part online article "Charming Python:
Functional programming in Python" by David Mertz discusses currying,
closures, and other aspects of functional programming. It can be found at
the following URLs.

www-106.ibm.com/developerworks/library/l-prog.html
www-106.ibm.com/developerworks/library/l-prog2.html
www-106.ibm.com/developerworks/library/l-prog3.html

Lenard Lindstrom
"<%s@%s.%s>" % ("len-l.", "telus", "net")







More information about the Python-list mailing list