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 PEP: 309
Title: Partial Function Application Title: Partial Function Application
Version: $Revision$ Version: $Revision$
Last-Modified: $Date$ Last-Modified: $Date$
Author: Peter Harris <scav@blueyonder.co.uk> 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 callable to be constructed from a callable and a partial argument list
(including positional and keyword arguments). (including positional and keyword arguments).
I propose a standard library module called "functional", to hold useful I propose a standard library module called "functional", to hold
higher-order functions, including the implementation of partial(). useful higher-order functions, including the implementation of
partial().
An implementation has been submitted to SourceForge [2]_.
Motivation Motivation
========== ==========
In functional programming, function currying is a way of implementing 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 function with N arguments is really a function with 1 argument that
returns another function taking (N-1) arguments. Function application returns another function taking (N-1) arguments. Function application
in languages like Haskell and ML works such that a function call:: in languages like Haskell and ML works such that a function call::
@ -38,7 +41,7 @@ actually means::
(((f x) y) z) (((f x) y) z)
This would be only an obscure theoretical issue except that in actual 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 terms of partial application of arguments to another function can be
both elegant and powerful, and in functional languages it is heavily both elegant and powerful, and in functional languages it is heavily
used. 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. thing when presented with a functor and less arguments than expected.
Python does not implement multi-argument functions by currying, so if Python does not implement multi-argument functions by currying, so if
you want a function with partially-applied arguments you would probably you want a function with partially-applied arguments you would
use a lambda as above, or define a named function for each instance. 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. However, lambda syntax is not to everyone's taste, so say the least.
Furthermore, Python's flexible parameter passing using both positional 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. application and do things that lambda cannot.
Rationale Example Implementation
========= ======================
Here is one way to do a create a callable with partially-applied 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:: provided by Scott David Daniels::
class partial(object): 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 constructor, and keyword arguments override and augment those provided
to the constructor. to the constructor.
Positional arguments, keyword arguments or both can be supplied at
when creating the object and when calling it.
Examples of Use Examples of Use
=============== ===============
@ -97,8 +104,8 @@ Examples of Use
So ``partial(operator.add, 1)`` is a bit like ``(lambda x: 1 + x)``. So ``partial(operator.add, 1)`` is a bit like ``(lambda x: 1 + x)``.
Not an example where you see the benefits, of course. Not an example where you see the benefits, of course.
Note too, that you could wrap a class in the same way, since Note too, that you could wrap a class in the same way, since classes
classes themselves are callable factories for objects. So in some cases, themselves are callable factories for objects. So in some cases,
rather than defining a subclass, you can specialise classes by partial rather than defining a subclass, you can specialise classes by partial
application of the arguments to the constructor. application of the arguments to the constructor.
@ -115,9 +122,10 @@ callbacks for Tkinter widgets on the fly::
win = Tk() win = Tk()
c = Canvas(win,width=200,height=50) c = Canvas(win,width=200,height=50)
c.pack() c.pack()
for colour in sys.argv[1:]: 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') b.pack(side='left')
win.mainloop() win.mainloop()
@ -129,16 +137,13 @@ Abandoned Syntax Proposal
I originally suggested the syntax ``fn@(*args, **kw)``, meaning the I originally suggested the syntax ``fn@(*args, **kw)``, meaning the
same as ``partial(fn, *args, **kw)``. 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 The @ sign is used in some assembly languages to imply register
indirection, and the use here is also a kind of indirection. 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. call it.
It has not been well-received, so I have withdrawn this part of the It was not well-received, so I have withdrawn this part of the
proposal. proposal. In any case, @ has been taken for the new decorator syntax.
Feedback from comp.lang.python and python-dev 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 * A curry class would indeed be a useful addition to the standard
library. 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(). name is now proposed to be partial().
* It maybe isn't useful enough to be in the built-ins. * 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. concerned it's a dead parrot.
I concur with calling the class partial rather than curry or closure, 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 throughout: some incorrect references to 'curry' have been left in
since that's where the discussion was at the time. 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 fn(*(cargs + fargs), **d)
return call_fn return call_fn
which he assures me is more efficient. You lose introspection and which he assures me is more efficient.
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.
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: cdef class curry:
@ -238,10 +241,16 @@ callables should be present in the standard library.
A standard library module ``functional`` should contain an A standard library module ``functional`` should contain an
implementation of ``partial``, and any other higher-order functions 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. 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 References
@ -249,6 +258,12 @@ References
.. [1] http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52549 .. [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 Copyright
========= =========