update from Peter Harris; minor edits

This commit is contained in:
David Goodger 2004-08-27 13:29:47 +00:00
parent 4957e14b72
commit 867839cff4
1 changed files with 44 additions and 29 deletions

View File

@ -1,5 +1,5 @@
PEP: 309
Title: Partial Function Application
Title: Partial Function Application
Version: $Revision$
Last-Modified: $Date$
Author: Peter Harris <scav@blueyonder.co.uk>
@ -18,15 +18,18 @@ This proposal is for a function or callable class that allows a new
callable to be constructed from a callable and a partial argument list
(including positional and keyword arguments).
I propose a standard library module called "functional", to hold useful
higher-order functions, including the implementation of partial().
I propose a standard library module called "functional", to hold
useful higher-order functions, including the implementation of
partial().
An implementation has been submitted to SourceForge [2]_.
Motivation
==========
In functional programming, function currying is a way of implementing
multi-argument functions in terms of single-argument functions. A
multi-argument functions in terms of single-argument functions. A
function with N arguments is really a function with 1 argument that
returns another function taking (N-1) arguments. Function application
in languages like Haskell and ML works such that a function call::
@ -38,7 +41,7 @@ actually means::
(((f x) y) z)
This would be only an obscure theoretical issue except that in actual
programming it turns out to be very useful. Expressing a function in
programming it turns out to be very useful. Expressing a function in
terms of partial application of arguments to another function can be
both elegant and powerful, and in functional languages it is heavily
used.
@ -52,8 +55,9 @@ always knows the number of arguments expected and can do the right
thing when presented with a functor and less arguments than expected.
Python does not implement multi-argument functions by currying, so if
you want a function with partially-applied arguments you would probably
use a lambda as above, or define a named function for each instance.
you want a function with partially-applied arguments you would
probably use a lambda as above, or define a named function for each
instance.
However, lambda syntax is not to everyone's taste, so say the least.
Furthermore, Python's flexible parameter passing using both positional
@ -61,11 +65,11 @@ and keyword presents an opportunity to generalise the idea of partial
application and do things that lambda cannot.
Rationale
=========
Example Implementation
======================
Here is one way to do a create a callable with partially-applied
arguments in Python. The implementation below is based on improvements
arguments in Python. The implementation below is based on improvements
provided by Scott David Daniels::
class partial(object):
@ -90,6 +94,9 @@ positional arguments are appended to those provided to the
constructor, and keyword arguments override and augment those provided
to the constructor.
Positional arguments, keyword arguments or both can be supplied at
when creating the object and when calling it.
Examples of Use
===============
@ -97,8 +104,8 @@ Examples of Use
So ``partial(operator.add, 1)`` is a bit like ``(lambda x: 1 + x)``.
Not an example where you see the benefits, of course.
Note too, that you could wrap a class in the same way, since
classes themselves are callable factories for objects. So in some cases,
Note too, that you could wrap a class in the same way, since classes
themselves are callable factories for objects. So in some cases,
rather than defining a subclass, you can specialise classes by partial
application of the arguments to the constructor.
@ -115,9 +122,10 @@ callbacks for Tkinter widgets on the fly::
win = Tk()
c = Canvas(win,width=200,height=50)
c.pack()
for colour in sys.argv[1:]:
b = Button(win, text=colour, command=partial(c.config,bg=colour))
b = Button(win, text=colour,
command=partial(c.config, bg=colour))
b.pack(side='left')
win.mainloop()
@ -129,16 +137,13 @@ Abandoned Syntax Proposal
I originally suggested the syntax ``fn@(*args, **kw)``, meaning the
same as ``partial(fn, *args, **kw)``.
At least there are no backwards-compatibility issues because the @
character isn't a legal operator in any previous versions of Python.
The @ sign is used in some assembly languages to imply register
indirection, and the use here is also a kind of indirection.
``f@(x)`` is not ``f(x)`` , but a thing that becomes ``f(x)`` when you
``f@(x)`` is not ``f(x)``, but a thing that becomes ``f(x)`` when you
call it.
It has not been well-received, so I have withdrawn this part of the
proposal.
It was not well-received, so I have withdrawn this part of the
proposal. In any case, @ has been taken for the new decorator syntax.
Feedback from comp.lang.python and python-dev
@ -157,7 +162,7 @@ Among the opinions voiced were the following (which I summarise):
* A curry class would indeed be a useful addition to the standard
library.
* It isn't function currying, but partial application. Hence the
* It isn't function currying, but partial application. Hence the
name is now proposed to be partial().
* It maybe isn't useful enough to be in the built-ins.
@ -181,7 +186,7 @@ not one single person has said they like it, so as far as I'm
concerned it's a dead parrot.
I concur with calling the class partial rather than curry or closure,
so I have amended the proposal in this PEP accordingly. But not
so I have amended the proposal in this PEP accordingly. But not
throughout: some incorrect references to 'curry' have been left in
since that's where the discussion was at the time.
@ -199,12 +204,10 @@ Carl Banks posted an implementation as a real functional closure::
return fn(*(cargs + fargs), **d)
return call_fn
which he assures me is more efficient. You lose introspection and
sub-classing that way, but these are maybe only marginal benefits and
not worth a performance hit, so this would also do as a reference
implementation.
which he assures me is more efficient.
I also coded the class in Pyrex::
I also coded the class in Pyrex, to estimate how the performance
might be improved by coding it in C::
cdef class curry:
@ -238,10 +241,16 @@ callables should be present in the standard library.
A standard library module ``functional`` should contain an
implementation of ``partial``, and any other higher-order functions
the community want. Other functions that might belong there fall
the community want. Other functions that might belong there fall
outside the scope of this PEP though.
The @ syntax proposal has been withrawn.
Patches for the implementation, documentation and unit tests (SF
patches 931005_, 931007_, and 931010_ respectively) have been
submitted but not yet checked in.
A C implementation by Hye-Shik Chang has also been submitted, although
it is not expected to be included until after the Python
implementation has proven itself useful enough to be worth optimising.
References
@ -249,6 +258,12 @@ References
.. [1] http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52549
.. [2] Patches 931005_, 931007_, and 931010_.
.. _931005: http://www.python.org/sf/931005
.. _931007: http://www.python.org/sf/931007
.. _931010: http://www.python.org/sf/931010
Copyright
=========