diff --git a/pep-0309.txt b/pep-0309.txt index fc20ffe98..168db4986 100644 --- a/pep-0309.txt +++ b/pep-0309.txt @@ -1,5 +1,5 @@ PEP: 309 -Title: Partial Function Application +Title: Partial Function Application Version: $Revision$ Last-Modified: $Date$ Author: Peter Harris @@ -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 =========