This assignment consists of reading, understanding, and modifying the metacircular evaluator in Chapter 4 of Abelson and Sussman. The assignment has lots of pieces. Be sure you start early. Moreover, some of the things you need to do are more subtle than you may first think.
Copy file ~offner/cs450/hw6/s450.scm to your hw6 subdirectory. That file contains all the relevant code from A&S, with small changes so that it runs in UMB Scheme. The name of the evaluator has been changed to s450. The invoking function is now (s450), not (driver-loop). This is the file we have been discussing in class.
You will create two files (which I will collect):
s450.scm This will be the (commented) scheme code that you write. It will be an edited version of the original s450.scm.
notes.txt This is for more discursive comments and discussion about the decisions you made in implementing the code for these problems, how you tested the code, and anything else that might be relevant.
1. (You should have already done this.) Play with the s450 evaluator:
% scheme s450.scm
==> (load “s450.scm”)
See how much of real Scheme is there. Write (in notes.txt) about what you found.
2. Rewrite xeval so that the handling of special forms is data directed. (This is Exercise 4.3 on page 374.) For each special form ( lambda, set!, cond, define, quote, … ) there is an appropriate semantic action—a scheme procedure A&S have already written. If you put those actions in a lookup table keyed by the symbol representing the special form then the cond in xeval will be much shorter, with a single table lookup for almost all the cases now listed separately. And you will be able to add special forms to s450 without editing xeval, which will now look something like this (in pseudocode):
let action = (lookup-action (type-of expression))
if lookup succeeded
invoke action, passing it the expression and the environment
else cond … ;; check for a few other types of expressions
You should write scheme functions like lookup-action and type-of to hide the lookup table implementation. (There are various ways to build a lookup table. You might want to review Section 3.3.3 (pages 266–271) for some ideas.) And for clarity below, we will sometimes refer to this lookup table as the “special form table”, since that really is what it is.
There’s nothing fancy going on here. And type-of is an extremely simple procedure that just takes the expression and tells you what special form it represents. It’s that simple.
To insert a new special form in the special form table, write the procedure install-special-form and call it this way (for example):
==> (install-special-form ‘set! (lambda (exp env) … ) )
Since install-special-form is not itself a special form in scheme, its first argument will be evaluated, and therefore generally needs to be quoted, as in the example above, to prevent this. (Indeed, it is possible to call install-special-form with the first argument being an unquoted expression that evaluates to the symbol for the form you are installing.) The second parameter, action, should be a lambda expression (or something that evaluates to a lambda expression) that takes two parameters, exp and env. xeval in s450 will arrange to pass those parameters when action is called. Since install-special-form is not a special form, that lambda expression will be evaluated in the environment in which install-special-form is called before being passed to the body of install-special-form.
Since install-special-form is called only for its side effect, it returns no useful information. However, to avoid generating garbage, have it return the name of the special form being installed.
Your implementation should ensure that a new special form cannot be installed using the name of a variable that is already defined.
Similarly, a special form (that is already in the special-form table) cannot be “reinstalled” using install-special-form.
[Optional] Once you have written install-special-form you can save yourself lots of time typing at the s450==> prompt to test your code by installing load as a special form. The code you need is in ~offner/cs450/hw6/load.s450. If you do this, (and you definitely don’t have to), you must include the text of load.s450 in your file s450.scm. Don’t (load “load.s450”).