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

For those who find Wikipedia a bit long-winded and enjoy LISPy syntax, lambda lifting performs the transformation:

  ((lambda <vars> <body>) <args>)
    ==lift==>
  ((lambda <vars+free> <body>) <args> <free>)
where <vars> are the variables (formal arguments) of the lambda function, <body> is its body, which contains some free variables, and <args> is the (actual) arguments in the application of the lambda function.

<Vars+free> is a new argument list also containing the free variables of the function (which are hence no longer free) and <free> denotes the formerly free variables, which have now been lifted to the scope of the caller.

For instance:

  ((lambda (x y) (F (G x y))) A B)
    ==lift==>
  ((lambda (x y F G) (F (G x y))) A B F G)
Because new actual arguments have to be passed to the transformed function, each place where the function is called has to be modified. Hence lambda lifting is a global program transformation.

The constraint of modifying all applications is trivially fulfilled when a lambda function is applied immediately, as above.




> the formerly free variables, which have now been lifted to the scope of the caller.

This risks obscuring the basic reason why the operation is called lambda lifting, which is that the lambda is "lifted" out of its local scope, to become a global function. I'm not really sure what you meant by that sentence. The free variables have always been in scope at the point where the function is called.

Here's a briefer description: http://wiki.c2.com/?LambdaLifting


Unfortunate choice of words.

However, I do not think that the description of "making a function global" is helpful, either. By lambda lifting, a closure becomes a combinator, a function without any free variables. It does not necessarily make that function "global".

The free variables, OTOH, move from the closure environment to the argument list of the function being lifted. That is, they are indeed "lifted" from the environment of the callee to the environment of the caller (where they may be bound or free).

Yes, that's not what the "lifting" in lambda lifting refers to. I apologize for the ambiguity.


The paper that introduced the term makes this very clear: http://citeseerx.ist.psu.edu/viewdoc/summary?doi=10.1.1.48.4...

"The process of flattening out a program involving local function de finitions, possibly with free variables, into a program consisting only of global function de finitions, we call lambda lifting"

I can't say I support your attempts to link "lifting" with some kind of motion of free variables. Variables, which were free in the function to be lifted, got their values from some enclosing scope. They still do, it's just that the binding is now explicit rather than lexical. The variables haven't moved, the plumbing has just changed.


Locations of variables do not move, but references to variables do:

  (lambda (F) 
    ((lambda (x) (F x)) A))
                  ^--- F in inner scope
                       of (lambda (x) ...)

  (lambda (F)
    ((lambda (x F*) (F* x)) A F))
                              ^--- F in outer scope
                                   of (lambda (x) ...)


You seem to be quite keen on the notion of lambda lifting a function "in place", so maybe you can explain why one would want to do that.

From where I'm standing, the lifting is about actually displacing the functions out of their current enclosing scope and into the global scope, possibly just out into an enclosing scope. But if you want to transform an anonymous function and then leave it in situ, that doesn't seem like lifting at all.

Closures explicitly don't come into the calculation, and it obviously only works in an immutable data setting (otherwise it might change the semantics of the code).


> You seem to be quite keen on the notion of lambda lifting a function "in place", so maybe you can explain why one would want to do that.

Have a look at lots of expanded LISP macros, there are nested lambdas all over the place, most of them applied in situ. Converting those applications as described above avoids the cost of closure creation and all that is left is a function call or, in case of tail application, a jump. It is a rather essential optimization in LISP.

Also: in situ application is useful for illustrating the principle. I have described the more general case somewhere else in this discussion.




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

Search: