Tutorial notes #10 for 4/30 or 5/1/2007

TA:       Stephen McCamant
Email:    smcc@mit.edu
Location: 36-113A or 36-115
Dynamic versus lexical scope

Scheme has "lexical scope", meaning that
the free variables in a procedure are
searched for in the code surrounding the
definition of the procedure. An
alternative rule is "dynamic scope", in
which free variables are looked for in
the environment where the procedure was

Write a procedure that returns the
symbol 'lexical if you evaluate it in
regular Scheme, but would return the
symbol 'dynamic if you evaluated it in a
dynamically-scope variant of Scheme.

(define (test-scope)
  (define x 'lexical)
  (define (func) x)
  (let ((x 'dynamic))

;; OR

(define (test-scope)
  (let ((x 'dynamic))
    ((let ((x 'lexical))
       (lambda () x)))))

;; or many other answers possible

You can use the environment model for
dynamic scope, but your procedures lose
their second bubbles.

Extending m-eval: "while"

For all you recovering C and Java
programmers, let's give Scheme a looping
syntax that looks like what those
languages provide.

(while <cond> <exp1> <exp2> ...)

The rules for evaluating while are as

1. Evaluate the condition
2. If it's #f, you're done
3. Otherwise, evaluate the <exp>s in
4. Go back to step 1

As an example, let's try writing
factorial using while.

(define (fact n)
  (let ((product 1))
    (while (> n 0)
           (set! product (* product n))
           (set! n (- n 1)))

Next, let's implement it in our
metacircular evaluator. First, we need
some syntax procedures:

(define (while? exp) ...)
(define (while-condition exp) ...)
(define (while-body exp) ...)

(define (while? exp) (tagged-list? exp 'while))
(define (while-condition exp) (cadr exp))
(define (while-body exp) (cddr exp))

We'll add a clause like this to m-eval:

((while? exp) (eval-while exp env))

Now, let's write eval-while:

(define (eval-while exp env)
  (if (m-eval (while-condition exp) env)
        (eval-sequence (while-body exp) env)
        (eval-while exp env))))

Alternatively, we could implement
"while" as syntactic sugar. What should
it be short for?

  (define loop
    (lambda ()
      (if <cond>
            <exp1> <exp2> ...

What would eval-while look like in this

(define (eval-while exp env)
   (make-begin (list
     (make-define 'loop
      (make-lambda '() (list
         (while-condition exp)
           (while-body exp)
             'loop '()))))
      'loop '()))) env))

What's one problem with this desugaring?

Bad things will happen if the programmer
is using a variable named "loop"
themselves, since the one the desugaring
defines will shadow it. This is a general
problem with expansions that define

Extending m-eval: "quasiquote"

Sometimes it's nice to have some data
that's mainly literal, but has small
variable sections, like a form letter.
We'd like to have a construct like
"quote", but with a way of getting out
of the quote and back to Scheme code.

(quote (1 2 3))
-> (1 2 3)

(quasiquote (1 (unquote (+ 1 1)) 3))
-> (1 2 3)

Suppose we have the following syntax

(define (quasiquoted? exp)
  (tagged-list? exp 'quasiquote))
(define (text-of-qq exp)
  (cadr exp))

(define (unquoted? exp)
  (tagged-list? exp 'unquote))
(define (body-of-unquote exp)
  (cadr exp))

and the following clause in m-eval:

((quasiquoted? exp)
 (eval-qq (text-of-qq exp) env))

What should eval-qq look like?

(define (eval-qq exp env)
    ((unquoted? exp)
     (m-eval (body-of-unquote exp) env))
    ((list? exp)
     (map (lambda (e)
            (eval-qq e env))
    (else exp)))

What do you think the following should

(The answers below are what Scheme really
does; I make no other claim for their
being logical.)

(quasiquote (quote (unquote (+ 1 1))))
;-> (quote 2)

(quasiquote (quasiquote (unquote (+ 1 1))))
;-> (quasiquote (unquote (+ 1 1)))

By the way, real Scheme does have
quasiquote and unquote, though they're
better known by short-hand syntaxes
analogous to ' for quote: ` (backquote,
usually on the same key as ~) for
quasiquote and , (comma) for unquote.

Extending m-eval: generalized assignment

We've seen it would be nice to have a
single mutation operation that operated
on any kind of expression: it would be
like set! on a variable, like set-car!
if applied to (car x), and so on.

(:= x 5)
same as (set! x 5)

(:= (car x) 5)
same as (set-car! x 5)

(:= (caar x) 5)
same as (set-car! (car x) 5)

(:= (car (last-pair lst) 5)
same as (set-car! (last-pair lst) 5)

(:= (last-pair lst) '())
Could this work?

As mentioned in Gerald's recitation last
week, this would require a significant
change to the evaluator. What kind of
change would be needed?

We'd have to add a new kind of value to
represent a result that can be assigned
to: such values would remember how to
change when they're assigned to, such as
with a procedure. More details in the
forthcoming recitation notes.