I am trying to use currying to make a simple functional add in Python. I found this curry decorator here.
def curry(func): def curried(*args, **kwargs):if len(args) + len(kwargs) >= func.__code__.co_argcount:return func(*args, **kwargs)return (lambda *args2, **kwargs2:curried(*(args + args2), **dict(kwargs, **kwargs2)))return curried@curry
def foo(a, b, c):return a + b + c
Now this is great because I can do some simple currying:
>>> foo(1)(2, 3)
6
>>> foo(1)(2)(3)
6
But this only works for exactly three variables. How do I write the function foo so that it can accept any number of variables and still be able to curry the result? I've tried the simple solution of using *args but it didn't work.
Edit: I've looked at the answers but still can't figure out how to write a function that can perform as shown below:
>>> foo(1)(2, 3)
6
>>> foo(1)(2)(3)
6
>>> foo(1)(2)
3
>>> foo(1)(2)(3)(4)
10
Arguably, explicit is better than implicit
:
from functools import partialdef example(*args):print("This is an example function that was passed:", args)one_bound = partial(example, 1)
two_bound = partial(one_bound, 2)
two_bound(3)
@JohnKugelman explained the design problem with what you're trying to do - a call to the curried function would be ambiguous between "add more curried arguments" and "invoke the logic". The reason this isn't a problem in Haskell (where the concept comes from) is that the language evaluates everything lazily, so there isn't a distinction you can meaningfully make between "a function named x
that accepts no arguments and simply returns 3" and "a call to the aforementioned function", or even between those and "the integer 3". Python isn't like that. (You could, for example, use a zero-argument call to signify "invoke the logic now"; but that would break special cases aren't special enough
, and require an extra pair of parentheses for simple cases where you don't actually want to do any currying.)
functools.partial
is an out-of-box solution for partial application of functions in Python. Unfortunately, repeatedly calling partial
to add more "curried" arguments isn't quite as efficient (there will be nested partial
objects under the hood). However, it's much more flexible; in particular, you can use it with existing functions that don't have any special decoration.