[Python-checkins] python/nondist/peps pep-0309.txt,1.4,1.5

goodger at users.sourceforge.net goodger at users.sourceforge.net
Sat Feb 28 14:09:32 EST 2004


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
  
  




More information about the Python-checkins mailing list