Last clab we increased the power of our mini-evaluator by adding the ability to inherit primitive procedures from the underlying scheme environment. This involved supplying a mini-apply that just invoked Drscheme's apply on the Drscheme primitive and the list of operand values evaluated in our environment. It also involved binding a procedure name in our mini-eval environment to the drscheme primitive.
Having stolen + and - from Drscheme, there is no reason to stop there. If you like, you can think of these primitives as being supplied in the machine language of the machine we are writing our mini-eval to run on. Let's steal some more primitive procedures. This means we want to grab a bunch of stuff to form an initial environment. We will do this in a somewhat more organized way so that adding and removing primitives will be relatively easy. For more power, we want lots of primitives. If we want to look at environments in detail, we may not want to clutter it up with primitives we do not need.
Think about and add the following to your definition window.
We increased the power of our mini-evaluator by adding the ability to inherit primitive procedures from the underlying scheme environment. This involved supplying a mini-apply that just invoked Drscheme's apply on the Drscheme primitive and the list of operand values evaluated in our environment. It also involved binding a procedure name in our mini-eval environment to the drscheme primitive.
One way to think about this is to consider the primitives inherited as being supplied in the machine language of the machine we are writing our mini-eval to run on. The truth is that what we did will work for any function defined in the underlying scheme environment. For example:
Given an expression, exp, and an environment, env, mini-eval sets up a case based analysis of exp. Once it recognizes what kind of expression exp is, mini-eval farms out the work to an appropriate function to carry out the task in environment env.
Your task for the rest of today is to add sequence (begin ...) and cond to our mini-evaluator.
Recall that cond works as follows:
(cond (p1 act1) (p2 act2) ... (pn actn)) where each p is a
predicate and each act is one or more actions to be taken if the
corresponding p is the first p that is not #f. The pairs (p act) are
called clauses. Conditionals are special forms because, they do not
evaluate all their arguments first. That is p1 is evaluated. If p1
is not #f, then act1 is evaluated (act1 may be a sequence of actions)
and none of the rest of the conditional is evaluated. If p1 is #f,
then act1 is not evaluated; p2 is evaluated. If p2 is not #f, then
act 2 is evaluated and none of the rest of the conditional is
evaluated. If p2 is #f then p3 ....
In their evaluator, SICP handles conditionals by doing if first and then converting conditionals to nested ifs. I want you to try to do conditionals directly in the style of the evaluator so far i.e. case-based analysis using appropriate abstraction barriers, etc. Possible names for these might be: conditional?, clauses, no-clauses?, first-clause, rest-clauses, predicate, actions, else-clause?, last-exp?, first-exp, rest-exps.
I added a few more primitives in addition to cond and begin. Here is a sample run: