update from Peter Harris, plus spell-check & edit
This commit is contained in:
parent
9ddde8f432
commit
49afb661db
102
pep-0309.txt
102
pep-0309.txt
|
@ -8,25 +8,26 @@ Type: Standards Track
|
||||||
Content-Type: text/x-rst
|
Content-Type: text/x-rst
|
||||||
Created: 08-Feb-2003
|
Created: 08-Feb-2003
|
||||||
Python-Version: 2.4
|
Python-Version: 2.4
|
||||||
Post-History: 10-Feb-2003
|
Post-History: 10-Feb-2003, 27-Feb-2003
|
||||||
|
|
||||||
|
|
||||||
Abstract
|
Abstract
|
||||||
=========
|
========
|
||||||
|
|
||||||
This proposal is for a built-in closure or curry type for Python that
|
This proposal is for a standard curry type for Python that
|
||||||
allows a new callable to be constructed from another callable and a
|
allows a new callable to be constructed from a callable and a
|
||||||
partial argument list (including positional and keyword arguments). A
|
partial argument list (including positional and keyword arguments).
|
||||||
concise syntax shorthand for curried functions is suggested
|
|
||||||
(tentatively).
|
|
||||||
|
|
||||||
Note: after feedback on comp.lang.python, I am persuaded that the most
|
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
|
accurate term for this is a 'curry' rather than a 'closure', so the
|
||||||
amended since the first version of this PEP.
|
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.
|
||||||
|
|
||||||
|
|
||||||
Motivation
|
Motivation
|
||||||
===========
|
==========
|
||||||
|
|
||||||
Curried functions are useful as functional 'sections' or as convenient
|
Curried functions are useful as functional 'sections' or as convenient
|
||||||
anonymous functions for use as callbacks.
|
anonymous functions for use as callbacks.
|
||||||
|
@ -49,7 +50,7 @@ We need something better.
|
||||||
|
|
||||||
|
|
||||||
Rationale
|
Rationale
|
||||||
==========
|
=========
|
||||||
|
|
||||||
Here is one way to do a curry in Python::
|
Here is one way to do a curry in Python::
|
||||||
|
|
||||||
|
@ -59,8 +60,11 @@ Here is one way to do a curry in Python::
|
||||||
self.fn, self.args, self.kw = (fn, args, kw)
|
self.fn, self.args, self.kw = (fn, args, kw)
|
||||||
|
|
||||||
def __call__(self, *args, **kw):
|
def __call__(self, *args, **kw):
|
||||||
d = self.kw.copy()
|
if self.kw:
|
||||||
d.update(kw)
|
d = self.kw.copy()
|
||||||
|
d.update(kw)
|
||||||
|
else:
|
||||||
|
d = kw
|
||||||
return self.fn(*(self.args + args), **d)
|
return self.fn(*(self.args + args), **d)
|
||||||
|
|
||||||
Note that when the curry is called, positional arguments are
|
Note that when the curry is called, positional arguments are
|
||||||
|
@ -78,17 +82,16 @@ Update: a recipe almost exactly like this has been in the Python
|
||||||
Cookbook for quite some time, at
|
Cookbook for quite some time, at
|
||||||
http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52549.
|
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.
|
||||||
|
|
||||||
Tentative Syntax Proposal
|
|
||||||
==========================
|
|
||||||
|
|
||||||
I know syntax proposals have the odds stacked against them, and
|
Abandoned Syntax Proposal
|
||||||
introducing new punctuation characters is frowned upon, but I think
|
=========================
|
||||||
curries may be a sufficiently powerful abstraction to deserve it.
|
|
||||||
|
|
||||||
I suggest the syntax ``fn@(*args, **kw)``, meaning the same as
|
I originally suggested the syntax ``fn@(*args, **kw)``, meaning the same
|
||||||
``curry(fn, *args, **kw)``. I have no idea what havoc this would
|
as ``curry(fn, *args, **kw)``.
|
||||||
wreak on the parser.
|
|
||||||
|
|
||||||
At least there are no backwards-compatibility issues because the @
|
At least there are no backwards-compatibility issues because the @
|
||||||
character isn't a legal operator in any previous versions of Python.
|
character isn't a legal operator in any previous versions of Python.
|
||||||
|
@ -119,9 +122,12 @@ Convenience functions ::
|
||||||
|
|
||||||
nextarg = sys.argv.pop@(0)
|
nextarg = sys.argv.pop@(0)
|
||||||
|
|
||||||
|
It has not been well-received, so I am not pursuing this as a serious
|
||||||
|
proposal.
|
||||||
|
|
||||||
|
|
||||||
Feedback from comp.lang.python
|
Feedback from comp.lang.python
|
||||||
===============================
|
==============================
|
||||||
|
|
||||||
Among the opinions voiced were the following (which I summarise):
|
Among the opinions voiced were the following (which I summarise):
|
||||||
|
|
||||||
|
@ -136,7 +142,15 @@ 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 maybe isn't useful enough to be in the builtins.
|
* It maybe isn't useful enough to be in the built-ins.
|
||||||
|
|
||||||
|
* The idea of a module called ``functional`` was well received, and
|
||||||
|
there are other things that belong there (for example function
|
||||||
|
composition).
|
||||||
|
|
||||||
|
* For completeness, another curry class that appends curried arguments
|
||||||
|
after those supplied in the function call (maybe called
|
||||||
|
``rightcurry``) has been suggested.
|
||||||
|
|
||||||
I agree that lambda is usually good enough, just not always. And I
|
I agree that lambda is usually good enough, just not always. And I
|
||||||
want the possibility of useful introspection and subclassing.
|
want the possibility of useful introspection and subclassing.
|
||||||
|
@ -151,13 +165,6 @@ dead parrot.
|
||||||
I concur with calling the class curry rather than closure, so I have
|
I concur with calling the class curry rather than closure, so I have
|
||||||
amended this PEP accordingly.
|
amended this PEP accordingly.
|
||||||
|
|
||||||
I think it's best as a builtin type rather than in a separate standard
|
|
||||||
library module, because it's simple and general enough. It may not be
|
|
||||||
an idiom that is very common in Python programming at the moment, but
|
|
||||||
I think that's because you have to code it yourself if you want it.
|
|
||||||
If added as a built-in feature, we would soon be wondering how we
|
|
||||||
managed without it.
|
|
||||||
|
|
||||||
Carl Banks posted an implementation as a real functional closure::
|
Carl Banks posted an implementation as a real functional closure::
|
||||||
|
|
||||||
def curry(fn, *cargs, **ckwargs):
|
def curry(fn, *cargs, **ckwargs):
|
||||||
|
@ -176,32 +183,45 @@ than a built-in curry class.
|
||||||
I also coded the class in Pyrex::
|
I also coded the class in Pyrex::
|
||||||
|
|
||||||
cdef class curry:
|
cdef class curry:
|
||||||
|
|
||||||
cdef object fn, args, kw
|
cdef object fn, args, kw
|
||||||
|
|
||||||
def __init__(self, fn, *args, **kw):
|
def __init__(self, fn, *args, **kw):
|
||||||
self.fn=fn
|
self.fn=fn
|
||||||
self.args=args
|
self.args=args
|
||||||
self.kw = kw
|
self.kw = kw
|
||||||
|
|
||||||
def __call__(self, *args, **kw):
|
def __call__(self, *args, **kw):
|
||||||
if self.kw: # from Python Cookbook version
|
if self.kw: # from Python Cookbook version
|
||||||
d = self.kw.copy()
|
d = self.kw.copy()
|
||||||
d.update(kw)
|
d.update(kw)
|
||||||
else:
|
else:
|
||||||
d=kw
|
d=kw
|
||||||
return self.fn(*(self.args + args), **d)
|
return self.fn(*(self.args + args), **d)
|
||||||
|
|
||||||
but I'm guessing that there would be minimal performance improvement
|
The performance gain in Pyrex is less than 100% over the nested function
|
||||||
since it compiles to a load of Python API calls.
|
implementation, since to be fully general it has to operate by Python API
|
||||||
|
calls. Any C implementation will be unlikely to be much faster, so the
|
||||||
|
case for a builtin coded in C is not very strong.
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Summary
|
Summary
|
||||||
========
|
=======
|
||||||
|
|
||||||
I maintain that curry should be a built-in, with the semantics as
|
I prefer that curry should be a built-in, with the semantics as
|
||||||
described, whether as a function or a class.
|
described, whether as a function or a 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. These other functions fall outside this PEP though.
|
||||||
|
|
||||||
The @ syntax proposal is withdrawn.
|
The @ syntax proposal is withdrawn.
|
||||||
|
|
||||||
|
Since this proposal is now much less ambitious, I'd like to aim for
|
||||||
|
inclusion in Python 2.3.
|
||||||
|
|
||||||
|
|
||||||
Copyright
|
Copyright
|
||||||
=========
|
=========
|
||||||
|
|
Loading…
Reference in New Issue