Korman Center 104C
In this assignment, you will modify the metacircular interpreter we saw in class. Successfully completing this assignment requires reading and understanding a medium-sized program written by someone else. If you do not have a good understanding of how the interpreter works, please review the material covered in lecture and in the book. Diving straight in to the homework without this understanding is going to make your task much more difficult.
We have provided you with a shell for your solution
here. Please extract this tarball in your
directory and immediately commit the resulting
hw2 directory. You can do this
$ cd ~/cs550/git $ wget 'https://www.cs.drexel.edu/~mainland/courses/cs550-201435/homework/hw2.tar.gz' $ tar xf hw2.tar.gz $ git add hw2 $ git commit -m "Initial check-in for homework 2."
All your changes should be made to the file
mceval.rkt. Be sure to commit
your work to the repository.
You can compile your code into a running interpreter by typing make
make does not complete successfully, it means your
code does not compile. Code that does not compile will receive a zero.
We have included several test for your convenience. Passing all provided tests
does not guarantee full credit, but failing tests does guarantee less than full
credit. You can run the tests by typing make run-tests in
This assignment is worth 100 points. There are 116 possible points.
Note: Problem 1 is due separately from problems 2–7. No late days may be used for Problem 1.
There are then two ways you can test your evaluator evaluator:
Type make and run the resulting binary, named
mceval program will repeatedly read in a Scheme expression and pass it to
your interpreter for evaluation.
From DrRacket, call the
top-mceval function with an expression, like this:
I used the second approach. I also made judicious use of
to debug my implementation.
There are three ways to extend the interpreter:
You should only add a special form when it is absolutely necessary. Most of the
time, the standard Scheme evaluation rules are exactly what you want. Solving a
problem by adding a definition rather than a new special form is also much
easier and avoids cluttering up your
newline to print out intermediate expressions! This is
extremely helpful when debugging.
Submit the solutions to this problem only in a file named
problem1.txt in the
hw2 subdirectory of your git repository.
What representation does the metacircular evaluator use for environments?
Please be specific. An English description will suffice; however, your answer will be stronger if you also provide examples.
define contains the list of primitives supported by the
metacircular interpreter? Please name the variable.
This is Exercise 4.14 from SICP.
Eva Lu Ator and Louis Reasoner are each experimenting with the metacircular
evaluator. Eva types in the definition of
map, and runs some test programs
that use it. They work fine. Louis, in contrast, has installed the system
map as a primitive for the metacircular evaluator. When he tries
it, things go terribly wrong. Explain why Louis’s
map fails even though Eva’s
This is Exercise 4.2a from SICP.
Louis Reasoner plans to reorder the
cond clauses in
eval so that the clause
for procedure applications appears before the clause for assignments. He argues
that this will make the interpreter more efficient: Since programs usually
contain more applications than assignments, definitions, and so on, his modified
eval will usually check fewer clauses than the original
identifying the type of an expression.
What is wrong with Louis’s plan? (Hint: What will Louis’s evaluator do with
(define x 3)?)
setup-environment is used to create the initial global
environment used by the metacircular interpreter. For later problems, it will be
convenient to add your own definitions to the initial global environment. The
most convenient way to do this is to call
eval-definition with the appropriate
arguments from within the function
setup-environment. If you were to add a
definition in this manner, what arguments would you pass to
add the following top-level
define to the initial global environment? You may
give your answer in the form of a Scheme expression.
Add the following primitives:
error. 1 point each.
error primitive should take no arguments and abort the interpreter with
the message “Metacircular Interpreter Aborted” (without the quotes).
or(20 points total)
Add support for
or to your interpreter (10 points each). Be sure
your implementation adheres to the Scheme language standard (see
in terms of how the arguments to
or are evaluated and in terms of
what value is returned.
You will probably want to use the
Remember that the metacircular interpreter cannot interpret
let(20 points total)
This is Exercise 4.6 from SICP.
Let expressions are derived expressions, because
is equivalent to
Implement a syntactic transformation
let->combination that reduces evaluating
let expressions to evaluating combinations of the type shown above, and add the
appropriate clause to
eval to handle let expressions.
display to print out the result of
let->combination to make sure
you get it right! I did not get it right the first time…
delay(20 points total)
Add support for
delay to your interpreter, where
expressions are only evaluated once when
For full credit, you must support call-by-need evaluation, which only evaluates
delay‘ed expressions once.
If your implementation is call-by-name but otherwise correct, you will receive 10 points. You do not need to submit both a call-by-name and a call-by-need implementation for full credit; just the call-by-need version will do.
It is highly recommended that you implement the call-by-name version first.
We recommend you use memoization to implement call-by-need
The implementations of both the call-by-name and call-by-need versions of force and delay were discussed in lecture. The easiest path to success will follow that implementation.
Your solution must demonstrate that you understand the underlying mechanisms for
implementing lazy evaluation. Therefore, you should not use Racket’s
delay or equivalent syntax macros in your solution.
Add support for the following stream functions to your interpreter:
You should be able to complete this problem with either the call-by-name or
call-by-need implementation of
delay. That is, you can receive
full credit for this problem even if you did not receive full credit for Problem
Your streams should be strict in the head of the stream and lazy in the tail. Note that Racket streams are lazy in both the head and the tail.
Your implementation must use your
delay from Problem 5. You may
not use Racket’s
delay or equivalent syntax macros in your
How long did it take you to complete problems 2–6? Please tell us in a comment
at the top of
mceval.rkt. You must tell us how long each problem took you to
receive the point.