Skip to content

Instantly share code, notes, and snippets.

Embed
What would you like to do?
KISS Python curry
#!/usr/bin/env python
def curry(func):
"""
Decorator to curry a function, typical usage:
>>> @curry
... def foo(a, b, c):
... return a + b + c
The function still work normally:
>>> foo(1, 2, 3)
6
And in various curried forms:
>>> foo(1)(2, 3)
6
>>> foo(1)(2)(3)
6
This also work with named arguments:
>>> foo(a=1)(b=2)(c=3)
6
>>> foo(b=1)(c=2)(a=3)
6
>>> foo(a=1, b=2)(c=3)
6
>>> foo(a=1)(b=2, c=3)
6
And you may also change your mind on named arguments,
But I don't know why you may want to do that:
>>> foo(a=1, b=0)(b=2, c=3)
6
Finally, if you give more parameters than expected, the exception
is the expected one, not some garbage produced by the currying
mechanism:
>>> foo(1, 2)(3, 4)
Traceback (most recent call last):
...
TypeError: foo() takes exactly 3 arguments (4 given)
"""
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
if __name__ == "__main__":
import doctest
doctest.testmod()
@blurrcat

This comment has been minimized.

Copy link

commented Dec 5, 2016

Fantastic! Thanks!

You may use functools.wraps to make the intermediate curried functions look like the original function.

from functools import wraps

def curry(func):
    """
    >>> @curry
    ... def foo(a, b, c):
    ...     return a + b + c
    >>> foo(1)
    <function __main__.foo>
    """
    @wraps(func)
    def curried(*args, **kwargs):
        if len(args) + len(kwargs) >= func.__code__.co_argcount:
            return func(*args, **kwargs)

        @wraps(func)
        def new_curried(*args2, **kwargs2):
            return curried(*(args + args2), **dict(kwargs, **kwargs2))

        return new_curried

    return curried

Now instead of showing <function __main__.curry.<locals>.curried.<locals>.<lambda>> for foo(1), we have the expected representation of the function. This can make debugging easier.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.