Curried functions
Robert Brewer
fumanchu at amor.org
Sun Jun 6 15:54:22 EDT 2004
Holger Türk wrote:
> a common pattern to write curried functions (i.e. without the
> need for a special partial application syntax, like in PEP 309)
> is like in this example:
>
> def functionLock (lk):
> def transform (fn):
> def lockedApply (*argl, **argd):
> lk.acquire ()
> try:
> fn (*argl, **argd)
> finally:
> lk.release ()
> return lockedApply
> return transform
>
> PEP 318 (decorators) contains some other examples.
> I wonder if someone else than me would appreciate a syntax
> like this:
>
> def functionLock (lk) (fn) (*argl, **argd):
> lk.acquire ()
> try:
> fn (*argl, **argd)
> finally:
> lk.release ()
>
> It would even enable us to write curried function definitions
> like this one:
>
> def f (*a) (x=1, **b) (*c, **d):
> [...]
>
> Current approaches about currying or partial application
> can't handle the latter in a simple/transparent way.
>
> Will it be hard to implement the feature?
> Are there any reasons that this syntax/concept is a bad idea?
I realize you're demonstrating by example, but I can't see why the first block wouldn't be written:
def functionLock (lk, fn):
def lockedApply (*argl, **argd):
lk.acquire ()
try:
fn (*argl, **argd)
finally:
lk.release ()
return lockedApply
...that is, I can't recall a case where I've doubly-nested a function like your example.
Anyway, a def like:
def f (*a) (x=1, **b) (*c, **d):
[...]
seems...limiting, I guess. The developer of 'f' doesn't always know exactly which arguments consumers are going to want to partially apply, in which order or groupings. A more generic approach would alleviate (if not completely remove) the need to nest. I'd rather see a consumer-side solution to partial application, where your example function is defined straightforwardly:
def functionLock(lk, fn, *argl, **argd):
lk.acquire()
try:
fn(*argl, **argd)
finally:
lk.release()
and the consumer decides when to supply arguments. They could decide to write:
f_lock = partial(functionLock, lk)
for func in func_set:
f_lock(func, 1, 2, 3)
or their purposes might be better served by applying two args "up front":
locked_f = partial(functionLock, lk, fn)
for i in range(10):
locked_f(i, i + 1)
It depends on the context.
Robert Brewer
MIS
Amor Ministries
fumanchu at amor.org
More information about the Python-list
mailing list