Hacker News new | past | comments | ask | show | jobs | submit login

So say I have a first-order language (where functions are not values). You can write:

    def foo(x): return x + 1
But not:

    def bar(baz, x): return baz(x+1)
That is to say, you pass integers around ('x' above) as values, but not functions. In a minimal higher order language, like C, you can pass functions around like values. Ie: baz could be a pointer to a function in the second line above, which is called by bar.

Now, what happens when you have nested functions?

    def foo():
        def bar(y):
            return y + 1
        return bar
You can't do this in C, but conceptually that's not much different than just defining foo and bar as two separate top-level functions.

But what happens when the inner function refers to a local variable of the outer function?

    def foo():
        x = 1
        def bar(y):
            return x + 1
        return bar
How does 'bar' know what 'x' is? You might ask, why would you want to do this? Well, say you have a function map(fun, list). Map takes a function and a list. It returns a list, each element of which is the value yielded by calling fun with an element in list. Eg:

    def foo(x): return x + 1
    map(foo, [1, 2, 3]) # -> [2, 3, 4]
Map can be defined as:

    def map(fun, list):
        result = []
        foreach item in list:
            result.append(fun(item))
So back to the example, you might want to write something like:

    def foo(list):
        x = some_calculation()
        def bar(y): return x + y
        return map(bar, list)
In other words, the function that you pass to map needs to know not just the current element of the list, but some other information that is held in a local variable in the parent function. This case is very common when using map as replacement for "for" loops (note how in a loop you can refer to the local variables of your function inside the body of the loop).

Now technically the name of the language feature that lets you capture the value of local variables in child functions is "lexically scoped lambda" or something along those lines. A closure is just the most common way to implement the language feature, but people often just use "closure" to refer to the language feature itself.

In a compiler that uses closures, the example above would be translated into code something like:

    class _closure_bar: 
        this.x = Nil

       def _closure_bar(x):
           this.x = x           

       def operator() (y):
           return this.x + y

    def foo(list):
        x = some_calculation()
        bar = new _closure_bar(x)
        return map(bar, list)
    
Instead of passing around a function as a function pointer like in C, you pass around a callable object whose members are the local variables of the parent function captured by the inner function, and which when called executes the body of the inner function.

Now, there is some additional complexity which occurs when an inner function modified the value of a local variable of an outer function. Languages like Python just disallow such modification, which is why people complain about Python not having "full lambdas". Languages like Common Lisp and Scheme add another indirection for local variables that are captured + assigned-to in an inner function.




Join us for AI Startup School this June 16-17 in San Francisco!

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: