CS 2135: Lab 5


Given the confusion that existed at the end of Tuesday's class, this lab will have you work on a related yet separate problem from what we were doing in class on Tuesday. We will clarify the material from the end of Tuesday's class on Thursday.

Lab Motivation and Goals

This lab will have you write a simple compiler for one stage in the process of converting regular programs to web scripts. It is designed to give you practice implementing compilers (programs which transform programs to other programs).


Context: "The Lambda Lifter"

We have been working on CPS because it shows us how to transform standard (tree-like) programs into programs in which all calls to functions are in tail position. The motivation for this is that web scripts are programs in which all calls to functions are in tail position.

Consider what CPS has bought us. Initially, we had a textual pizza program that looked like:

   (display-order
     (prompt-read-many1 promptlist1)
     (prompt-read-many2 promptlist2))

If we CPSed this program, we would get:

   (prompt-read-many1/k promptlist1
     (lambda (answers1)
       (prompt-read-many2/k promptlist2
         (lambda (answers2)
           (display-order answers1 answers2)))))

This says that prompt-read-many1/k will do its usual processing, then call (lambda (answers1) ...) to continue the program.

In contrast, the web program looked like:

  (define (prompt-name-addr-page)
     ...
     (prompt-order-script name addr))

  (define (prompt-order-script name addr)
     ...
     (display-order-script name addr size style toppings))

  (define (display-order-script name addr size style toppings)
     ...)

What's the difference between these two versions? The web version doesn't have any anonymous functions! Each continuation [(lambda (answers1) ...) and (lambda (answers2) ...) in the CPSed version] is an explicitly-named function (aka a script) in the web version. In particular, prompt-order-script is (lambda (answers1) ...) and display-order-script is (lambda (answers2) ...). Think about how you wrote your HTML forms: in the ACTION item, you gave the name of a script to call, not a lambda expression.

So, if we want to convert the CPSed version into a true set of scripts, we need to give an explicit name to each lambda expression and replace turn each use of a lambda with its new explicit name. Thus, our CPSed version should become:

   (prompt-read-many1/k promptlist1 new-prompt-order-script)

   (define (new-prompt-order-script answers1)
     (prompt-read-many2/k promptlist2 new-display-order-script))

   (define (new-display-order-script answers2)
     (display-order answers1 answers2))

This process is called "lambda lifting", since you "lift" lambdas to the top level and give them names. This lab asks you to implement a lambda lifter.

Exercises:

  1. Develop a function lambda-lift which consumes and expr and returns two pieces of information: a new version of the expr (with no proc statements in it) and a new list of defs (make-defs) that give names to the procs that were in expr.

        lambda-lift : expr -> expr and list-of-defs 

    Here are some examples of what lambda-lift should return:

    Implement this for the number?, var?, plus?, proc?, and apply? cases.

    You need to know about two new Scheme features to implement this function:

    Hints: Start simple! Follow the template for expr. Ask yourself what each call to lambda-lift returns. Use the examples above to help you develop the program.

  2. Consider our original CPSed program from above (with (lambda (answers1) ...) and (lambda (answers2) ...) and the result (also shown above) after lambda-lifting this program. Remember that a compiler must never change the final answer that a program produces. Ask yourself what would happen if you ran the lifted version of the CPS program. Would it run properly? If not, why not and what do you need to do to fix the problem? [Hint: something does go wrong ...]