Graceful Partial Functions in Python

Functions as they are in Python are great, but there's one small glitch: unlike in Haskell/Ocaml/F#, they're not "curried" automatically when we don't pass enough arguments to them.

Say we've got a function which takes two arguments, a and b, and adds them together. We'll call this function add, like so:

def add(a, b):  
    return a + b

In Ocaml (and Haskell, I think!) the equivalent to this would be:

let add a b = a + b  

In Ocaml, we'd be able to save a "specialised" version of this function like so:

let addOne = add 1  

This function has been specialised in that instead of adding any two numbers together, it adds one to any number. This is called Currying: we're filling in some (but not all) of the parameters, and making the result callable.

(N.B. we can be more specific with the above code, like so:

let addOne n = add 1 n;;  

This is a process known as eta-expansion, and is inserted automatically in most cases by the Ocaml compiler.)

Unfortunately, Python doesn't have this convenience. In the Ocaml example, we use add 1 as a "partial function" to express the fact that we're populating some -- not all -- of the parameters. Python does have support for partial functions, but they're never created automatically:

>>> addOne = add(1)
Traceback (most recent call last):  
  File "<stdin>", line 1, in <module>
TypeError: add() missing 1 required positional argument: 'b'  

Python sees the syntax f(x) as unambiguously attempting to call an object f with parameter x. This is beneficial in many cases, but at times it seems like the graceful partial function creation might be easier to work with.

To fit this need, I wrote a decorator makepartial which applies to any function with a fixed number of arguments. These can be keyword or positional arguments, but there must be a fixed number -- no *args or **kwargs in the definition.

To make a function curryable, apply this decorator:

@makepartial
def add(a, b):  
    return a + b

A trivial test case shows the functions will execute as planned or degrade gracefully into partial functions:

add(2, 3)  # -> 5

add2 = add(2)  
add2(3) == 5  # -> 5  

I've embedded the gist containing this decorator below. It's really only 4 functional lines of code on lines 21-24 -- the rest is documentation and boilerplate for making it work as a decorator.