Code Ninja: Lambda functions
|Anonymous functions aren’t just 4Chan meetups – they’re also a way to create cleaner code.
If we were trying to come up with a name to make something sound excessively mathematical, we couldn’t do better than lambda calculus. The phrase conjures up a picture of a stern-faced maths teacher peering over his glasses while wearing a tweed jacket with leather-patched elbows.
The reason it sounds so confusing is because it hails from a time when computing was little more than an obscure branch of maths that only interested academics and the military.
Lambda calculus was created as mathematicians were struggling to understand computation, and what its limits were. It’s a very simple way of specifying programs, and because it’s simple, it’s easy to reason about mathematically.
Basically, lambda calculus is a way of forming computer programs out of functions with two restrictions. Firstly, the functions don’t have a name, and secondly they can only take one argument. Functions that follow these rules are known as Lambda functions. Let’s take a look at this in Python, which supports lambda functions with the lambda statement:
>>> add2 = lambda x: x+2
This creates a function that takes one argument (x) and returns the number x+2. Python imposes additional restrictions on lambda functions: they can only contain one statement and that statement must return a value (which not all statements do in Python). Because they only contain one statement, they don’t need the return keyword to specify what they return. Whatever is after the colon is the statement, and the function will return whatever it evaluates to.
In this case, we’ve assigned the function to a variable called add2. You don’t have to assign the function to a variable and most of the time it’s more useful not to (remember that we said functions don’t have names?), but we’ll get onto that in a bit. You can run the function with:
>>> add2(1)
3
So far, this just looks like a slightly awkward way of creating functions. You could be forgiven for wondering why Python includes this slightly odd theoretical concept. One of the advantages of lambda functions in Python is that they can be a very convenient way of specifying a function that will only be used once. Typically, this when a function is needed as a parameter.
For example, take a look at the following function from the XBMC remote elsewhere in this issue’s coding section:
def get_artists():
data = xbmc.AudioLibrary.GetArtists()
return sorted(data[‘result’][‘artists’], key=lambda k: k[‘label’])
Here, the Python function sorted() can take an argument called key which specifies a function that is called on each element to be sorted that returns the value that the items should be sorted on. In this case, key is a lambda function that takes a dictionary as its parameter and outputs the particular item from that dictionary that we want to sort on. We could define a function in the usual Python way (by using def and giving it a name). However the lambda notation is clearer and simpler.
Hello again, Mr Turing!
Lambda calculus wasn’t created as a convenient shorthand. It was created as a method of defining computation. Like Turing machines, lambda calculus is a computationally complete language. That means that anything that can be computed, can be defined using lambda calculus (not necessarily in Python’s restricted version of it though).
Obviously this isn’t possible if each function can only operate on a single value. Lambda calculus also allows chaining of functions to build up more complex operations. For example, you could create a function to add two values together with:
>>> add = lambda x: lambda y: y+x
>>> add(3)(2)
5
This chaining – also known as currying – enables you to build up functions of arbitrary complexity. It also enables you to build functions by fixing particular parameters in other lambda functions. For example (following on from the previous session):
>>> add10 = add(10)
>>> add10(1)
11
This is rarely used in Python, but it can be used in a few ways. For example, we could use it to create logging functions for system and application errors in Python 3:
>>> p_log = lambda er: lambda msg: print(er, msg)
>>> p_sys_err = p_log(“System error:”)
>>> p_app_err = p_log(“Application error:”)
>>> p_sys_err(“operating system problem”)
System error: operating system problem
>>> p_app_err(“the application has crashed”)
Application error: the application has crashed
You need to use Python3 because in previous versions of Python, print() didn’t return a value, and so couldn’t be used as a lambda statement (in Python3, print() is a function that returns None).
In Python, the restriction to only one statement means you can’t loop through data, since there can’t be any code blocks. However, you can still use if statements using a slightly different format:
x if <conditions> else y
For example, you could use this to return the lowest number in a pair using:
>>> min = lambda x: x[0] if x[0]<x[1] else x[1]
>>> min([3,5])
>>> 3
Python doesn’t need lambda functions. Everything you do with them could also be achieved without them. However, there are several places where they can be used to make your code more readable. This is usually in places where a function object is passed (like in the sort example above).
Beyond Python
Most programming languages allow anonymous functions (you can argue about whether an anonymous function with more than one argument is really a lambda function). The only commonly used general purpose languages without them are C (though they are supported in Clang) and Fortran. No other common language has the single statement restriction of Python.
The syntax and terminology varies from language to language, but they’re usually used for cases similar to those we’ve looked at here when functions need passing as arguments in other functions, particularly in callbacks (which we looked at in LV007).