recitation 21: more evaluator practice -------------------------------------------------------------------- suppose we change the call in m-apply from: (extend-environment (procedure-parameters procedure) arguments (procedure-environment procedure)) to: (extend-environment (procedure-parameters procedure) arguments the-global-environment) * does this change how we draw environment diagrams? how? yes, now all frames will hang directly from the global environment. the environment pointer of the procedure is ignored. * write the simplest expression (or set of expressions) you can, which evaluate to a different value with the original m-apply versus the modified m-apply. (define x 5) ((lambda (x) x) 2) original m-apply --> 2 modified m-apply --> 5 NOTE: the value of the sugared version of this expression: (let ((x 2)) x) will depend on the implementation of let in the evaluator. (why?) -------------------------------------------------------------------- (incr! <var> <exp>) (define x 10) (incr! x 3) x --> 13 * change the evaluator to add incr! * now add decr! does it have to be a special form? yes decr! must be a special form. we can't let the application clause handle this expression, because we don't want to evaluate <var>. * make a (general) list of the things that need to be changed/added when you extend the evaluator to add a new special form. - write expression detector, accessor & constructor functions - write necessary helper functions - add clause to m-eval - modify m-apply or other parts of the evaluator, as necessary -------------------------------------------------------------------- practice using the "named-let" special form: (let <var> <bindings> <body>) The <bindings> and <body> are just as in ordinary let, except that <var> is bound within <body> to a procedure whose body is <body> and whose parameters are the variables in the <bindings>. Thus, one can repeatedly execute the <body> by invoking the procedure named <var>. (let foo ((x 5)) (display x) (if (< x 1) 'done (foo (- x 1)))) * draw an environment diagram for this example. what variables does the procedure foo need access to?
NOTE: this is one possible solution. there are other variations that also correctly implement the specified semantics. * how would you use named-let to iteratively reverse a list? (hint: use 2 variables in the <bindings>) (let reverse ((rest '(1 2 3 4)) (answer '())) (if (null? rest) answer (reverse (cdr rest) (cons (car rest) answer)))) * you're asked to add named-let to the evaluator for project 5... -------------------------------------------------------------------- practice using the "letrec" special form: (letrec ((<var1> <exp1>) (<var2> <exp2>) ... ) <body>) the <var>s are bound in a new frame to (initially) undefined values. the <exp>s are evaluated in the resulting environment (in unspecified order), and bound to the corresponding <var>. the <body> is evaluated in the resulting environment, and the value of the last expression in <body> is returned. each binding of a <var> has the entire `letrec' expression as its region, making it possible to define mutually recursive procedures. * what does it mean to say that m-eval and m-apply are "mutually-recursive procedures"? even? calls odd?, and odd? calls even? the environment for each procedure must contain the definition for the other. One restriction on "letrec" is very important: it must be possible to evaluate each <exp> without assigning or referring to the value of any <var>. If this restriction is violated, then it is an error. The restriction is necessary because Scheme passes arguments by value rather than by name. In the most common uses of `letrec', all the <exp>s are lambda expressions and the restriction is satisfied automatically. (letrec ((even? (lambda (n) (if (zero? n) #t (odd? (- n 1))))) (odd? (lambda (n) (if (zero? n) #f (even? (- n 1)))))) (even? 5)) * draw an environment diagram for this example. what variables do the procedures even? and odd? need access to?
* use letrec to create a toy expression with 3 mutually-recursive procedures. show that your expression does not result in an infinite loop. * you're asked to add letrec to the evaluator for project 5... -------------------------------------------------------------------- * can you rewrite (desugar) a "named-let" using "let"? * can you rewrite (desugar) a "named-let" using "letrec"? -------------------------------------------------------------------- (dolist (<var> <lst>) <body>) <var> is bound to each element in <lst> sequentially and <body> is executed once for each binding. the expression returns the value of the last expression in body for the binding of <var> to the last element of <lst>. (dolist (x '(1 2 3 4)) (display (* x x))) * is dolist a special form? why or why not? * change the evaluator to add dolist --------------------------------------------------------------------