Issue13430
This issue tracker has been migrated to GitHub,
and is currently read-only.
For more information,
see the GitHub FAQs in the Python's Developer Guide.
Created on 2011-11-18 16:01 by markonervo, last changed 2022-04-11 14:57 by admin. This issue is now closed.
Messages (15) | |||
---|---|---|---|
msg147882 - (view) | Author: Marko Nervo (markonervo) | Date: 2011-11-18 16:01 | |
I think it would be very usefull to add a curry function to the functools module. It should be like this. def curry(func, *args, **kwargs): if (len(args) + len(kwargs)) >= func.__code__.co_argcount: return func(*args, **kwargs) return (lambda *x, **y: curry(func, *(args + x), **dict(kwargs, **y))) This function allows you to create curried functions or methods in two main ways: (1) >>> def adder(x, y, z): ... return (x + y + z) >>> adder = curry(adder) (2) >>> @curry ... def adder(x, y, z): ... return (x + y + z) Curried functions could be used as follow. >>> adder(2, 3, 4) >>> adder(2, 3)(4) >>> adder(2)(3)(4) >>> adder(z = 4)(2, 3) # etc, etc, etc... Best regards, Marco. |
|||
msg147885 - (view) | Author: Ezio Melotti (ezio.melotti) * | Date: 2011-11-18 16:14 | |
This sounds similar to http://wiki.python.org/moin/PythonDecoratorLibrary#Pseudo-currying Do you have a concrete use case for this? |
|||
msg147886 - (view) | Author: Antoine Pitrou (pitrou) * | Date: 2011-11-18 16:15 | |
You can use functools.partial for similar effect. Not sure what a dedicated curry() primitive would improve. |
|||
msg147887 - (view) | Author: Alex Gaynor (alex) * | Date: 2011-11-18 16:16 | |
This already exists, as functools.partial: http://docs.python.org/library/functools.html#functools.partial |
|||
msg147897 - (view) | Author: Marko Nervo (markonervo) | Date: 2011-11-18 16:59 | |
In [1]: import functools In [2]: def adder(x, y, z): ...: return (x + y + z) ...: In [3]: adder = functools.partial(adder) In [4]: adder(2)(3)(4) --------------------------------------------------------------------------- TypeError Traceback (most recent call last) /home/marko/<ipython console> in <module>() TypeError: adder() takes exactly 3 arguments (1 given) No, it can't be replaced using functools.partial. |
|||
msg147901 - (view) | Author: Éric Araujo (eric.araujo) * | Date: 2011-11-18 17:03 | |
To go back to your original message: > I think it would be very usefull to add a curry function to the functools module. For what use cases? > Curried functions could be used as follow. >>> adder(2, 3, 4) >>> adder(2, 3)(4) >>> adder(2)(3)(4) >>> adder(z = 4)(2, 3) # etc, etc, etc... I don’t know the curry concept from other languages, but I’m experienced with Python and don’t like this idea at all. A function returns something; the returned value being callable or not is a property of that value, not of the function. The examples above look confusing to me. I think you should discuss your use cases on the python-ideas mailing list. |
|||
msg147904 - (view) | Author: Ezio Melotti (ezio.melotti) * | Date: 2011-11-18 17:08 | |
FWIW there is a somewhat related thread that proposed a new syntax for curried functions: http://mail.python.org/pipermail/python-ideas/2009-March/003220.html |
|||
msg147911 - (view) | Author: Marko Nervo (markonervo) | Date: 2011-11-18 18:02 | |
I totally disagree with the syntax for curried function, but I think a curry function is perfect for the functools module and I also think it could be useful at least as functools.partial. In addition, a lot of languages support currying, such as Haskell, Scala, Javascript... However, here an example less confusional >>> adder = curry(lambda (x, y): (x + y)) >>> adder3 = adder(3) >>> adder3(4) 7 >>> adder3(5) 8 Currying let you defining new functions on other functions. This is a common practice in functional programming (point-free style). So, why not? |
|||
msg147912 - (view) | Author: Antoine Pitrou (pitrou) * | Date: 2011-11-18 18:07 | |
> However, here an example less confusional > > >>> adder = curry(lambda (x, y): (x + y)) > >>> adder3 = adder(3) > >>> adder3(4) > 7 > >>> adder3(5) > 8 > > Currying let you defining new functions on other functions. But so does functools.partial. So the question is, what use case does it help that functools.partial doesn't? |
|||
msg147913 - (view) | Author: Ezio Melotti (ezio.melotti) * | Date: 2011-11-18 18:09 | |
In that thread Guido said: """ Haskell has this too, perhaps even more extreme: there's not really such a thing in Haskell as a function of N arguments (N > 1). "f a b = ..." defines a function f of one argument a which returns another function ("f a") of one argument b. And so on. That doesn't mean we need to copy this idea in Python. """ New features require a valid use case before being included, and I'm afraid "why not?" is not valid :) (Also nothing prevents you to define your own curry function/decorator and use it where you need it.) |
|||
msg147918 - (view) | Author: Marko Nervo (markonervo) | Date: 2011-11-18 19:38 | |
> But so does functools.partial. So the question is, what use case does it > help that functools.partial doesn't? Sure, it's common `defining new functions on other functions`... more times. Here a stupid example with fold (our reduce). @curry def fold(function, start, sequence): if len(sequence) == 0: return start else: return fold(function, function(start, sequence[0]), sequence[1:]) Now, someone could be define a generic summer function by fold. import operator as op summer = fold(op.add) Now, an other programmer could be use summer for defining listsummer (a function which sum only list), as follow. listsummer = summer([]) In addition, curry is cleaver than functools.partial. summer = functools.partial(fold, op.add) listsummer = functools.partial(summer, []) However, it is an additional feature. Nobody forces you to use it, but if you need it... Yeah, you could rewrite it each time, but why? It is perfect in functools (: |
|||
msg147919 - (view) | Author: Antoine Pitrou (pitrou) * | Date: 2011-11-18 19:43 | |
> Sure, it's common `defining new functions on other functions`... more > times. Here a stupid example with fold (our reduce). > > @curry > def fold(function, start, sequence): > if len(sequence) == 0: > return start > else: > return fold(function, function(start, sequence[0]), sequence[1:]) > > Now, someone could be define a generic summer function by fold. > > import operator as op > > summer = fold(op.add) Right... so you defined these helper functions (curry, fold) just to... define a generic summer function? Really? I understand that fold() and curry() may look pretty to functional languages people, but they don't solve any real-world problems that Python doesn't already solve in a neater way. You will have to try a bit harder and showcase examples of *useful* code that are made significantly easier through the use of curry(). (no, generic summer functions are *not* real-world use cases. They are homework exercises for CS students, at best) |
|||
msg147921 - (view) | Author: Marko Nervo (markonervo) | Date: 2011-11-18 20:20 | |
> You will have to try a bit > harder and showcase examples of *useful* code that are made > significantly easier through the use of curry(). Curry is a more advanced functools.partial. So, it could be used *at least* as partial, but it is more powerfull, usable and readable. I think it's a valid reason; if it isn't, I haven't anything else to say. |
|||
msg147939 - (view) | Author: Petri Lehtinen (petri.lehtinen) * | Date: 2011-11-19 12:25 | |
@markonervo: Have you tried the pointfree library: http://pypi.python.org/pypi/pointfree/ ? I think it's exactly what you're asking for. The only case I've ever needed currying was managing callback soup in async code. And even then, functools.partial() was perfectly enough. I don't think this would be useful in Python stdlib, so -1 from me. |
|||
msg147975 - (view) | Author: Collin Winter (collinwinter) * | Date: 2011-11-20 03:56 | |
I assume I was added to this thread since I wrote the functional module, so I'll give my take in that capacity. IMO Python doesn't need a more general version of partial(); indeed, I question the need for partial() as it is today. Querying Google Code Search for code using partial, I haven't found any usages in the wild where partial() makes code more readable than simply defining a new function. partial() is almost always a loss for readability. |
History | |||
---|---|---|---|
Date | User | Action | Args |
2022-04-11 14:57:23 | admin | set | github: 57639 |
2011-11-20 03:56:20 | collinwinter | set | messages: + msg147975 |
2011-11-19 12:25:15 | petri.lehtinen | set | nosy:
+ petri.lehtinen messages: + msg147939 |
2011-11-18 20:20:21 | markonervo | set | messages: + msg147921 |
2011-11-18 19:43:33 | pitrou | set | messages: + msg147919 |
2011-11-18 19:38:14 | markonervo | set | messages: + msg147918 |
2011-11-18 18:09:21 | ezio.melotti | set | messages: + msg147913 |
2011-11-18 18:07:39 | pitrou | set | messages: + msg147912 |
2011-11-18 18:02:54 | markonervo | set | messages: + msg147911 |
2011-11-18 17:08:04 | ezio.melotti | set | messages:
+ msg147904 stage: resolved |
2011-11-18 17:03:04 | eric.araujo | set | messages: + msg147901 |
2011-11-18 16:59:41 | markonervo | set | messages: + msg147897 |
2011-11-18 16:16:17 | alex | set | status: open -> closed nosy: + alex messages: + msg147887 resolution: not a bug |
2011-11-18 16:15:36 | pitrou | set | nosy:
+ pitrou messages: + msg147886 |
2011-11-18 16:14:01 | ezio.melotti | set | nosy:
+ ezio.melotti messages: + msg147885 versions: + Python 3.3, - Python 2.7, Python 3.4 |
2011-11-18 16:01:33 | markonervo | create |