>Scott David Daniels wrote: >>>Chris Perkins wrote: >>>>Random idea of the day: How about having syntax support for >>>>currying/partial function application, like this: >>>>func(..., a, b) >>>>func(a, ..., b) >>>>func(a, b, ...) >>>> >>>>That is: >>>>1) Make an Ellipsis literal legal syntax in an argument list. >>>>2) Have the compiler recognize the Ellipsis literal and transform >>>> the function call into a curried/parially applied function. >>>>So the compiler would essentially do something like this: >>>> >>>>func(a, ...) ==> curry(func, a) >>>>func(..., a) ==> rightcurry(func, a) >>>>func(a, ..., b) ==> rightcurry(curry(func,a), b) > >The interaction of this with keyword args and omitted args is >problematic (as is the case for rightcurry, in fact). I can't >think of a good way to explain what _should_ happen for a >function defined as def function(*args, **kwargs): ... when you: > > def fun(bug, frog, verb): ... > f1 = function(1, ..., frog=3) > f2 = f1(..., 4) > f2() > >Keywords were why I did no rightcurry definition in the first place; >I couldn't convince myself there was a good, obvious, resolution. >
I agree that it's not obvious what _should_ happen in complex cases. I wrote up a psuedo-implementation to play with, just to get a feel for it. It works only on @curryable functions, and I use "__" in place of "...". I think that's about as close as I can get in pure Python. def curryable(func): "This hurts my brain a little bit, but I _think_ it works." def proxyfunc(*args, **kwds): if list(args).count(Ellipsis) > 1: raise TypeError('Your mother was a hampster...') if Ellipsis in args: @curryable def curried(*a, **k): kwdict = kwds.copy() kwdict.update(k) epos = list(args).index(Ellipsis) return func(*(args[:epos] + a + args[epos+1:]), **kwdict) return curried return func(*args, **kwds) return proxyfunc def test(): __ = Ellipsis @curryable def fun(bug, frog, verb): print bug, frog, verb f1 = fun(1, __, frog=3) f2 = f1(__, 4) try: f2() except TypeError, e: print e # multiple values for keyword 'frog' f1 = fun(1, __, verb=3) f2 = f1(__, 4) f2() f2(verb=99) try: f1(__, 2, __) except TypeError, e: print e if __name__ == '__main__': test() After playing with this a bit, I found the semantics to be reasonably obvious once I got used to it; at least in the cases I tried. I'd be quite happy to have anything fishy throw an exception. Cases where I would actually use this would be quite simple, I think. On the other hand, I'm not convinced that this construct would be especially useful. I spent some time looking at uses of lambda in the standard library, hoping to find lots of examples where a (...) function would be more readable, but I eventually gave up. (Found dozens of cases where a list-comp or genexp would be better, though). While I think that func(x, ...) is more readable than partial(func, x), I'm not sure that I would use either of them often enough to warrant special syntax. If anyone disagrees, feel free to petition python-dev; I don't expect to pursue this any further. Thanks to all for your comments. Chris Perkins -- http://mail.python.org/mailman/listinfo/python-list