Interpreter Project

Extension B:

trace, untrace

Optional extension.
All parts due: NOON on Sunday, May 11th
Notes about extensions

Extension B, like other extensions, serves three purposes. The extensions will...

  1. ...give you a much more detailed understanding of the material.
  2. ...make your interpreter more complete.
  3. ...provide you a chance to earn some extra credit.
It is extremely important to note that you should not be attempting any of the Extensions unless you are completely finished with all previous parts. You will lose far more points for failing to complete required sections of the interpreter than you could possibly gain by completing all of the Extensions.

You may attempt to complete the Extensions at any point during the project. You do not need to attempt them after a specific required portion of the project. In addition, you should not run handin37 separately to hand in an extension: simply hand in the extension along with the next required section you complete.

Finally, since these extensions are considered "advanced" features, you will receive far less guidance in completing them than you will receive for the required portions of the project. This does not mean that you cannot ask questions; rather, I will provide less information to you up front, forcing you to work out details on your own.

Implementing trace and untrace

Though it may not seem logical to implement trace and untrace before implementing lambda, you will actually be able to complete the entire implementation of these two functions without much of an idea of how lambda will eventually operate, and you can test your current implementation of trace on the primitive procedures. Of course, once you add lambda to your interpreter, you will want to go back and make sure that everything works. Chances are that, with one minor detail, your implementation should continue to work.

Play around with trace in DrRacket to make sure you understand how it works. Note that in DrRacket, you can trace functions that you write yourself, but you can not trace primitive functions, so you will need to write your own functions in order to experiment with trace. In our implementation, we will support tracing both our own functions and primitive functions.

You should also read the Racket documentation for trace. Select the entry that says:

A few pieces of advice:

  1. Your test for whether or not you are trying to apply a traced procedure should be done in eval‑application.
  2. Be sure you can handle expressions such as (trace a b c) (which traces all three functions); on its own, (trace) does nothing.
  3. Be sure you correctly handle what happens if an already-traced function is traced. For example (the colors are just for easy reading, you should not try to output specially colored text):
    > (define f (lambda (x) (+ x 1)))
    > (trace f)
    (f)
    > (f 5)
    |(f 5)
    |6
    6
    > (trace f)
    (f)
    > (untrace f)
    (f)
    > (f 5)
    6
  4. The "detail" that you may need to go back and fix when you get to lambda in Part 5 -- unless you anticipated well or read the documentation page -- is how to deal with nesting the output of traced procedures which call other traced procedures (or themselves recursively). You can test that out once you write lambda in Part 5.
  5. In addition to allowing tracing of primitive functions, your version of trace can be even more powerful than the built-in trace -- if you want it to be. In fact, you may find that it is actually easier to allow for this "more powerful" version than to try and mimic DrRacket's version. Once you are able to define your own procedures using lambda, you'll be able to trace procedures that are defined locally inside other procedures; the DrRacket version of trace will not let you do that.


Extension B may be completed at any stage of the final project and does not need to be turned in separately.