Currying in Python

Kiuhnm kiuhnm03.4t.yahoo.it
Sat Mar 17 02:21:32 CET 2012


Here we go.

--->
def genCur(f, unique = True, minArgs = -1):
    """ Generates a 'curried' version of a function. """
    def geng(curArgs, curKwargs):
        def g(*args, **kwargs):
            nonlocal f, curArgs, curKwargs, minArgs;    # our STATIC data

            if len(args) or len(kwargs):
                # Allocates data for the next 'g'. We don't want to modify our
                # static data.
                newArgs = curArgs[:];
                newKwargs = dict.copy(curKwargs);

                # Adds positional arguments.
                newArgs += args;

                # Adds/updates keyword arguments.
                if unique:
                    # We don't want repeated keyword arguments.
                    for k in kwargs.keys():
                        if k in newKwargs:
                            raise(Exception("Repeated kw arg while unique = True"));
                newKwargs.update(kwargs);

                # Checks whether it's time to evaluate f.
                if minArgs >= 0 and minArgs <= len(newArgs) + len(newKwargs):
                    return f(*newArgs, **newKwargs);    # f has enough args
                else:
                    return geng(newArgs, newKwargs);    # f needs some more args
            else:
                return f(*curArgs, **curKwargs);    # the caller forced the evaluation
        return g;
    return geng([], {});

def cur(f, minArgs = -1):
    return genCur(f, True, minArgs);

def curr(f, minArgs = -1):
    return genCur(f, False, minArgs);

# Simple Function.
def f(a, b, c, d, e, f, g = 100):
    print(a, b, c, d, e, f, g);

# NOTE: '<====' means "this line prints to the screen".

# Example 1.
c1 = cur(f)(1);
c2 = c1(2, d = 4);              # Note that c is still unbound
c3 = c2(3)(f = 6)(e = 5);       # now c = 3
c3();                           # () forces the evaluation              <====
c4 = c2(30)(f = 60)(e = 50);    # now c = 30
c4();                           # () forces the evaluation              <====

print("\n------\n");

# Example 2.
c1 = curr(f)(1, 2)(3, 4);           # curr = cur with possibly repeated
                                    # keyword args
c2 = c1(e = 5)(f = 6)(e = 10)();    # ops... we repeated 'e' because we <====
                                    # changed our mind about it!
                                    # again, () forces the evaluation

print("\n------\n");

# Example 3.
c1 = cur(f, 6);             # forces the evaluation after 6 arguments
c2 = c1(1, 2, 3);           # num args = 3
c3 = c2(4, f = 6);          # num args = 5
c4 = c3(5);                 # num args = 6 ==> evalution                <====
c5 = c3(5, g = -1);         # num args = 7 ==> evaluation               <====
                            # we can specify more than 6 arguments, but
                            # 6 are enough to force the evaluation

print("\n------\n");

# Example 4.
def printTree(func, level = -1):
    if level == -1:
        printTree(cur(func), level + 1);
    elif level == 6:
        func(g = '')();     # or just func('')()
    else:
        printTree(func(0), level + 1);
        printTree(func(1), level + 1);

printTree(f);

print("\n------\n");

def f2(*args):
    print(", ".join(["%3d"%(x) for x in args]));

def stress(f, n):
    if n: stress(f(n), n - 1)
    else: f();          # enough is enough

stress(cur(f2), 100);
<---

Kiuhnm



More information about the Python-list mailing list