python/nondist/peps pep-0309.txt,1.4,1.5

Update of /cvsroot/python/python/nondist/peps In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv5776 Modified Files: pep-0309.txt Log Message: update from Peter Harris Index: pep-0309.txt =================================================================== RCS file: /cvsroot/python/python/nondist/peps/pep-0309.txt,v retrieving revision 1.4 retrieving revision 1.5 diff -C2 -d -r1.4 -r1.5 *** pep-0309.txt 21 Feb 2004 16:32:30 -0000 1.4 --- pep-0309.txt 28 Feb 2004 19:09:16 -0000 1.5 *************** *** 1,4 **** PEP: 309 ! Title: Function Currying Version: $Revision$ Last-Modified: $Date$ --- 1,4 ---- PEP: 309 ! Title: Partial Function Application Version: $Revision$ Last-Modified: $Date$ *************** *** 9,13 **** Created: 08-Feb-2003 Python-Version: 2.4 ! Post-History: 10-Feb-2003, 27-Feb-2003 --- 9,13 ---- Created: 08-Feb-2003 Python-Version: 2.4 ! Post-History: 10-Feb-2003, 27-Feb-2003, 22-Feb-2004 *************** *** 15,28 **** ======== ! This proposal is for a curry constructor for Python that ! allows a new callable to be constructed from a callable and a ! partial argument list (including positional and keyword arguments). ! ! Note: after feedback on comp.lang.python, I am persuaded that the most ! accurate term for this is a 'curry', so the terminology has been ! amended since the first version of this PEP. I propose a standard library module called "functional", to hold useful ! higher-order functions, including the curry() class. --- 15,24 ---- ======== ! 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(). *************** *** 30,35 **** ========== ! Curried functions are useful as functional 'sections' or as convenient ! anonymous functions for use as callbacks. In some functional languages, (e.g. Miranda) you can use an expression --- 26,46 ---- ========== ! In functional programming, function currying is a way of implementing ! 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:: ! ! f x y z ! ! 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 ! terms of partial application of arguments to another function can be ! both elegant and powerful, and in functional languages it is heavily ! used. In some functional languages, (e.g. Miranda) you can use an expression *************** *** 41,50 **** thing when presented with a functor and less arguments than expected. ! Python has more flexible argument-passing, and so function currying cannot ! be implicit in the same way. Instead, a Python programmer ! will probably either define another named function or use a lambda. ! But lambda syntax is not to everyone's taste, to say the least. ! We need something better. --- 52,63 ---- 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. ! However, lambda syntax is not to everyone's taste, so say the least. ! Furthermore, Python's flexible parameter passing using both positional ! and keyword presents an opportunity to generalise the idea of partial ! application and do things that lambda cannot. *************** *** 52,60 **** ========= ! Here is one way to do a create a curried callable in Python. The ! implementation below is based on improvements provided by Scott David ! Daniels:: ! class curry(object): def __init__(*args, **kw): --- 65,73 ---- ========= ! Here is one way to do a create a callable with partially-applied ! arguments in Python. The implementation below is based on improvements ! provided by Scott David Daniels:: ! class partial(object): def __init__(*args, **kw): *************** *** 70,91 **** return self.fn(*(self.args + args), **d) ! Note that when the curried function is called, positional arguments are ! appended to those provided to the constructor, and keyword arguments ! override and augment those provided to the constructor. ! So ``curry(operator.add, 1)`` is a bit like ``(lambda x: 1 + x)``, and ! ``curry(Tkinter.Label, fg='blue')`` is a callable like the Tkinter ! Label class, but with a blue foreground by default. - I think a built-in class called ``curry`` that behaves the same way - would be very useful. ! Update: a recipe almost exactly like this has been in the Python ! Cookbook for quite some time, at ! http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52549. ! Update: It seems likely that a standard library implementation would ! be in Python, and would have to prove its worth there before making ! it into the built-ins. --- 83,125 ---- return self.fn(*(self.args + args), **d) ! (A recipe similar to this has been in the Python Cookbook for some ! time [1]_.) ! Note that when the object is called as though it were a function, ! positional arguments are appended to those provided to the ! constructor, and keyword arguments override and augment those provided ! to the constructor. ! 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, ! rather than defining a subclass, you can specialise classes by partial ! application of the arguments to the constructor. ! ! For example, ``partial(Tkinter.Label, fg='blue')`` makes Tkinter ! Labels that have a blue foreground by default. ! ! Here's a simple example that uses partial application to construct ! callbacks for Tkinter widgets on the fly:: ! ! from Tkinter import Tk, Canvas, Button ! import sys ! from functional import partial ! ! 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.pack(side='left') ! ! win.mainloop() *************** *** 93,98 **** ========================= ! I originally suggested the syntax ``fn@(*args, **kw)``, meaning the same ! as ``curry(fn, *args, **kw)``. At least there are no backwards-compatibility issues because the @ --- 127,132 ---- ========================= ! 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 @ *************** *** 104,134 **** call it. ! (The only other connection I can see with curry is that @ looks a bit ! like a section through a mushroom pakora.) ! ! ! Examples of Use ! --------------- ! ! Using closures as callbacks with bound arguments:: ! ! def handler(arg1, arg2, opt=0): ! #whatever... ! ! button1 = Button(window, text="Action A", ! command=handler@('A', '1')) ! button2 = Button(window, text="Action B", ! command=handler@('B', '2', opt=1)) ! ! Convenience functions :: ! ! nextarg = sys.argv.pop@(0) ! ! It has not been well-received, so I withdraw this part of the proposal. ! Feedback from comp.lang.python ! ============================== Among the opinions voiced were the following (which I summarise): --- 138,147 ---- call it. ! It has not been well-received, so I have withdrawn this part of the proposal. ! Feedback from comp.lang.python and python-dev ! ============================================= Among the opinions voiced were the following (which I summarise): *************** *** 136,140 **** * Lambda is good enough. ! * The @ syntax is ugly (so far, unanimous). * It's really a curry rather than a closure. There is an almost --- 149,153 ---- * Lambda is good enough. ! * The @ syntax is ugly (unanimous). * It's really a curry rather than a closure. There is an almost *************** *** 145,148 **** --- 158,164 ---- library. + * 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. *************** *** 151,155 **** composition). ! * For completeness, another curry class that appends curried arguments after those supplied in the function call (maybe called ``rightcurry``) has been suggested. --- 167,171 ---- composition). ! * For completeness, another object that appends partial arguments after those supplied in the function call (maybe called ``rightcurry``) has been suggested. *************** *** 161,170 **** weird. We have dictionary, list and tuple literals neatly differentiated by special punctuation -- a way of directly expressing ! curried function literals is not such a stretch. However, 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 curry rather than closure, so I have ! amended this PEP accordingly. Carl Banks posted an implementation as a real functional closure:: --- 177,193 ---- weird. We have dictionary, list and tuple literals neatly differentiated by special punctuation -- a way of directly expressing ! partially-applied function literals is not such a stretch. However, ! 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 ! throughout: some incorrect references to 'curry' have been left in ! since that's where the discussion was at the time. ! ! Partially applying arguments from the right, or inserting arguments at ! arbitrary positions creates its own problems, but pending discovery of ! a good implementation and non-confusing semantics, I don't think it ! should be ruled out. Carl Banks posted an implementation as a real functional closure:: *************** *** 177,185 **** return call_fn ! which he assures me is more efficient. All you lose with this ! implementation is introspection and sub-classing. These are only ! marginal benefits and not worth a performance hit, so this would also ! do as a reference implementation of a built-in curry function rather ! than a built-in curry class. I also coded the class in Pyrex:: --- 200,207 ---- 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. I also coded the class in Pyrex:: *************** *** 202,209 **** return self.fn(*(self.args + args), **d) ! The performance gain in Pyrex is less than 100% over the nested function ! implementation, since to be fully general it has to operate by Python API ! calls. For the same reason, a C implementation will be unlikely to be much ! faster, so the case for a built-in coded in C is not very strong. --- 224,232 ---- return self.fn(*(self.args + args), **d) ! The performance gain in Pyrex is less than 100% over the nested ! function implementation, since to be fully general it has to operate ! by Python API calls. For the same reason, a C implementation will be ! unlikely to be much faster, so the case for a built-in coded in C is ! not very strong. *************** *** 211,223 **** ======= ! I prefer that some means to curry functions should be a built-in, with the ! semantics as described, whether as a function or a callable class. However, ! it should do its apprenticeship in the standard library first. ! The standard library module ``functional`` should contain ``curry`` and ! ``rightcurry`` classes, and any other higher-order functions the community ! want. Other functions that might belong there fall outside this PEP though. ! The @ syntax proposal is withdrawn. --- 234,252 ---- ======= ! I prefer that some means to partially-apply functions and other ! 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 ! outside the scope of this PEP though. ! The @ syntax proposal has been withrawn. ! ! ! References ! ========== ! ! .. [1] http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52549
participants (1)
-
goodger@users.sourceforge.net