Self-currying functions

Dave Benjamin ramen at lackingtalent.com
Fri May 23 02:14:47 EDT 2003


In article <qsGya.27509$XV1.109 at nwrdny03.gnilink.net>, Carl Banks wrote:
> Dave Benjamin wrote:
>> The above nested lambda expression is what curried() creates and then
>> eval's. I'd like to do this without the need for an eval, but I am having
>> trouble building a for-loop to accomplish this.
> 
> Ah, there you go.  You're thinking iteratively when you should be
> thinking recursively.
>
> What I did in my solution was to simply look at it this way: you want
> to return a function that checks the number of args.  If there are
> enough, call it; otherwise, curry the function, and then recursively
> call the self-curry-maker on the curried function.

Beautiful. Now can you make it look like an airplane? ;)
Thanks for the wise words and speedy response!

The following is my response, adapted from your example to support Alex
Martelli's curry function (and as a result, curried named parameters). I'm
starting to find interesting uses I hadn't anticipated. Very grateful for
your help.

Peace,
Dave

# selfcurry.py

'''
>>> f = selfcurry(lambda w, x, *y, **z: (w, x, y, z))
>>> f(1, 3)
(1, 3, (), {})
>>> f(1)(3)
(1, 3, (), {})
>>> f(1)(2, 3)   
(1, 2, (3,), {})
>>> f(1, a=5)(2, 3)
(1, 2, (3,), {'a': 5})
>>> f(1, a=5)(2, 3, b=6)
(1, 2, (3,), {'a': 5, 'b': 6})
'''

from __future__ import nested_scopes

def curry(func, *create_time_args, **create_time_kwds):
    """
    Binds arguments to a function.
    
    Author: Alex Martelli
    Source: http://aspn.activestate.com/ASPN/Cookbook/Python/Recipe/52549
    """
    def curried_function(*call_time_args, **call_time_kwds):
        args = create_time_args + call_time_args
        kwds = create_time_kwds.copy()
        kwds.update(call_time_kwds)
        return func(*args, **kwds)
    
    return curried_function

def selfcurry(func, nargs=None):
    """
    Returns a function that curries itself.
    
    Authors: Carl Banks, Dave Benjamin
    Source:  http://groups.google.com/groups?hl=en&lr=&ie=UTF-8&frame=right&th=736757dcaeb50c2e#link2
    """    
    if nargs is None:
        nargs = func.func_code.co_argcount

    def call_if_enough_args(*args, **kwds):
        if len(args) < nargs:
            return selfcurry(curry(func, *args, **kwds), nargs - len(args))
        else:
            return func(*args, **kwds)

    return call_if_enough_args




More information about the Python-list mailing list