diff options
Diffstat (limited to 'js/games/nluqo.github.io/~bh/61a-pages/Lectures/4.2/old-MCE-questions')
-rw-r--r-- | js/games/nluqo.github.io/~bh/61a-pages/Lectures/4.2/old-MCE-questions | 144 |
1 files changed, 144 insertions, 0 deletions
diff --git a/js/games/nluqo.github.io/~bh/61a-pages/Lectures/4.2/old-MCE-questions b/js/games/nluqo.github.io/~bh/61a-pages/Lectures/4.2/old-MCE-questions new file mode 100644 index 0000000..d00120f --- /dev/null +++ b/js/games/nluqo.github.io/~bh/61a-pages/Lectures/4.2/old-MCE-questions @@ -0,0 +1,144 @@ +Here are several metacircular evaluator questions from past 60A final exams. +For each of these questions, you should go through these three steps: + +(a) Is this primarily a change to eval (based on the current environment) or + to apply (based on a procedure's execution environment)? + +(b) Which specific subprocedure should be changed? + +(c) Then write the code. + +The first two steps are most important! + +-------------------------------------------------- + +1. Modify the metacircular evaluator to accept a new kind of cond clause, +as explained below. We are interested in the situation in which some +expression is computed as the predicate part of a clause, and then if that +expression is non-nil, the same expression is part of the desired return +value. For example, suppose we have an association list like + +((I . 1) (V . 5) (X . 10) (L . 50) (C . 100) (D . 500) (M . 1000)) + +The tool we have for looking things up in such a list is assq, which +returns the entire pair whose car matches its argument: + +> (assq 'L roman-number-list) +(L . 50) + +Suppose we want to find the numeric value for a given letter. We could +define the following procedure: + +(define (value letter) + (cond ((assq letter roman-number-list) + (cdr (assq letter roman-number-list))) + (else nil))) + +but this involves computing the call to assq twice. Alternatively, +we could use a let outside the cond, but that's awkward if +the cond has several clauses and only one requires this value. +For example, using a let would be tricky if the example were + +(define (value letter-or-number) + (cond ((number? letter-or-number) letter-or-number) + ((assq letter-or-number roman-number-list) + (cdr (assq letter-or-number roman-number-list))) + (else nil))) + +Here is how this would look using the new syntax you are going to invent: + +(define (value letter-or-number) + (cond ((number? letter-or-number) letter-or-number) + ((assq letter-or-number roman-number-list) => cdr) + (else nil))) + +The first and third clauses are unchanged. The second clause uses the new +syntax. It has exactly three elements; the second of those three is the +keyword => to indicate the use of this syntax, and the third is an +expression whose value is a one-argument procedure (the symbol cdr). If the +value of the first expression is non-nil, then cond should evaluate the +third element and apply that function to the value of the first element. + + + +2. (This is the one we did in class.) + +(a) Modify the metacircular evaluator so that it always evaluates +the arguments in a procedure call from left to right, regardless +of the order of evaluation in the underlying Scheme. + +(b) Does your modified evaluator always evaluate the procedure +expression before it evaluates the argument expressions, regardless +of the underlying Scheme? For example, in evaluating the expression + +(foo a b) + +will your evaluator always look up FOO before looking up A? Explain +why or why not. + +(c) Show an example interaction with Scheme in which the result of the +interaction depends on whether or not the procedure expression is evaluated +before the argument expressions. + + + +3. Modify the metacircular evaluator to allow type-checking of arguments to +procedures. Here is how the feature should work. When a new procedure is +defined, a formal parameter can be either a symbol as usual or else a list +of two elements. In this case, the second element is a symbol, the name of +the formal parameter. The first element is an expression whose value is +a predicate function. That function should return #t if the argument +is valid. For example, here is a procedure foo that has type-checked +parameters num and list: + +> (define (foo (integer? num) ((lambda (x) (not (null? x))) list)) + (nth num list)) +FOO +> (foo 3 '(a b c d e)) +C +> (foo 3.5 '(a b c d e)) +Error: wrong argument type -- 3.5 +> (foo 2 '()) +Error: wrong argument type -- () + +In this example we define a procedure foo with two formal parameters, named +num and list. When foo is invoked, the evaluator will check to see that the +first actual argument is an integer and that the second actual argument is +not empty. The expression whose value is the desired predicate function +should be evaluated with respect to foo's defining environment. + + + +4. Suppose you have a procedure that takes several arguments, e.g., + +(define (foo a b c d e f) ...) + +Now you want to invoke this procedure. You are providing values explicitly +for the parameters a and b, but you have the remaining arguments in a list. +If you had all the arguments in a list, you could say + +(apply foo arglist) + +but instead you have to say something awkward like + +(apply foo (cons a-value (cons b-value arglist))) + +We'd like to invent a new notation, allowing you to invoke the procedure +by saying + +(foo a-value b-value . arglist) + +In this notation, arglist must be a symbol whose value is a list. Your job +is to modify the metacircular evaluator to accept this notation. + +NOTE 1: Although this looks similar to the notation + +(define (foo a b . args) ...) + +used to create a procedure that accepts variable numbers of arguments, it's +not the same feature. This time we're talking about the invocation +of the procedure, not the definition of the procedure. + +NOTE 2: You should assume that the (read) procedure has already taken +care of translating the dot notation into an improper list, which is what +you'll see as the expression to be evaluated. |