Partial application and currying

Currying, known in Python land as partial application, is a technique in which a function taking multiple arguments composes a function that takes fewer arguments (in most languages, reducing to one, although this is not the case in Python) by partially applying it to given parameters. For example, a function, sum, might be used to compose a new function called “plus_one” by currying it with the value of one. The composed function is not evaluated; it is returned as a function object which may then be applied to other parameters.

Python’s partial() is contained in the functools module (included since Python 2.5, I believe). The first argument passed must be the function to be curried, and the rest are positional or keyword arguments that will be used to curry the passed function.

A common case where partials are useful is in defining a compare function for a list. It often happens that the list must be sorted according to rules defined at runtime. A partial application can simplify the process, especially if there is a complex sort algorithm. Assume a list of Items, items. The list will be sorted according to get_sort_attribute(), which returns the name of the attribute of Item which will be used to perform the sort, and get_sort_direction, which returns either “desc” or “asc.” Rather than using a long series of if/else statements and calling the sort() method in various ways, partial() can be used to progressively modify the sort.

To sort a list this way, we might have something like:

(def compare(a, b):
    attr = get_sort_attribute()
    dir = get_sort_direction()
    value_a = getattr(a, attr)
    value_b = getattr(b, attr)
    if dir == 'desc':
        return cmp(value_b, value_a)
    else:
        return cmp(value_a, value_b)
items.sort(compare)

This can get pretty long-winded, especially if our function, compare, performs complex operations before performing the comparison. Here is the same thing using partial applications to compose our function instead:

from functools import partial
 
# Wrap getattr in a lambda so that can accept keyword arguments
attribute_getter = partial(lambda object, name:
    getattr(object, name), name=get_sort_attribute())
sort_fn = partial(items.sort, key=attribute_getter)
if get_sort_direction() == 'desc':
    sort_fn = partial(sort_fn, reversed=True)
sort_fn()

This is certainly more concise. I found a nice little currying function for Javascript here (edit: it was pointed out in a reader’s comment (here and at dzone) that this version of curry does not work on previously curried functions; below it is a modified version which will function as expected):

/*
function curry(fn, scope) {
    var scope = scope || window;
    var args = [];
    for (var i=2, len = arguments.length; i < len; ++i) {
        args.push(arguments[i]);
    };
    return function() {
        /* one big problem here is that the following statement
        is not returning the applied function. */
        fn.apply(scope, args);
    };
}
*/
 
function curry(fn, scope) {
    var scope = scope || window;
    var args = [];
    for (var i = 2; i &lt; arguments.length; i++) {
        args.push(arguments[i]);
    }
    return function() {
        // this takes care of the arguments problem
        var fn_args = [];
        for (var i = 0; i &lt; args.length; i++) {
            fn_args.push(args[i]);
        }
        for (var i = 0; i &lt; arguments.length; i++) {
            fn_args.push(arguments[i]);
        }
        // this takes care of the null return problem
        return fn.apply(scope, fn_args);
    };
}

I often use this in my Django web projects. I will include a basic error function which inserts an error message into an element with a particular id on the base template. Note that I use jQuery in the following examples.

function err(target, msg) {
    $('#' + target).html(msg);
}

In templates that extend that template, I can then use currying to modify that for a particular location defined in this template:

var err = curry(err, window, 'err_div_in_this_template');

I can further use this to create custom error callbacks for ajax functions:

var err404 = curry(err, window, "The server could not be contacted.");

Now, err404 is the equivalent of:

function err404() {
    $('#' + 'err_div_in_this_template').html("The server could not be contacted.");
}

Obviously, this is a pretty trivial example, but it does a good job of showing a real-world use for currying.

Leave a comment | Trackback
Dec 4th, 2007 | Posted in Programming
No comments yet.