CS 1 Fall 2007

Lab 7: Mutants Demand Environmental Evolution

Assigned: Monday, November 12, 2007
Due: Thursday, November 22, 2007, 02:00:00


You should have read through section 3.2 of SICP before beginning this lab.

Part @: Time Synopsis

  1. As you answer the problems below, make a note on how long you spent on each of the sections.

  2. If any of the individual problems took you notably more time than the rating stated, please identify them and write down your actual time spent. This will help us calibrate future problem sets.


Part A: Exercises

This lab is heavily weighted towards part A. Therefore, we don't expect you to complete all of these exercises before your recitation section, but you should at least attempt as many of them as possible. Should you have any difficulties working through these exercises, bring your questions to recitation.

  1. Complete the environment diagrams for the Scheme code given, with the following stipulations:.

    You should be able to load the partial environment diagrams given here into xfig and edit them. NOTE: there may be features in the partial environment diagrams which you do not need. Here are instructions for xfig for this lab. Of course, you're free to use a different drawing program (e.g. Dia or Visio or even Adobe Illustrator) as long as you save the results as a Postscript file (encapsulated Postscript or PDF format is fine too). This should be submitted to CS1man as usual.

    1. [10] Show the environment after executing this code.

      [Partial environment diagram] [xfig file]
      (define (a x)
        (- 5 (/ x (+ x 1))))
      (define (b x)
        (* x x (a (+ x 3))))
      (b 11)
      
    2. [20] Show the environment after executing this code.

      [Partial environment diagram] [xfig file]
      (define (compose f g)
         (lambda (arg) (f (g arg))))
      (define sqrt-plus1 (compose (lambda (x) (+ x 1)) sqrt))
      

      Hint: Be careful with the environment pointers of the lambda pairs; it's easy to point them to the wrong environment. Think about the order in which expressions get evaluated, and which environment each expression gets evaluated in.

    3. [30] Show the environment after executing this code.

      [Partial environment diagram] [xfig file]
      (define curry3op (lambda (x) (lambda (y) (lambda (z) (+ x y z)))))
      (define c1op ((curry3op 3) 4))
      
    4. [20] Show the environment after executing this code.

      [Partial environment diagram] [xfig file]
      (define (make-accum)
        (let ((val 0))  (lambda (x) (set! val (+ val x)))))
      (define a1 (make-accum))
      (define a2 (make-accum))
      (define a3 a1)
      

      Hint: (make-accum) is a function call, and a function call always creates a frame, even if no bindings need to be created in that frame.

      Hint 2: A let expression just creates a frame, immediately binds some values, and executes the code in its body. If you desugar it to a lambda you'll get the same effect.

    5. [20] Show the environment after executing this code:

      [Partial environment diagram] [xfig file]
      (define (make-counter) 
        (let ((val 0))
          (cons (lambda () val) 
                (lambda () (set! val (+ val 1))))))
      (define a (make-counter))
      (define a-count (cdr a))
      (define a-value (car a))
      

      Hint: Remember that lambda expressions always have their environment pointer set to the environment in which they were evaluated, so you should keep track of the current environment at all times.

  2. For each of the following environment structures, give Scheme code which could produce it. NOTE: You are free to write code which would add other things in the environment beyond what is shown. Also, note that for each problem there may be more than one correct answer.

    1. [20]env1.gif
    2. [30]env2.gif
    3. [20]env3.gif
    4. [30] env4.gif

      NOTE: This one is slightly tricky. Hint: Can you make a data structure (not shown) that contains both lambda pairs?


  3. [20] What's wrong with these expressions?

    1. (set! 5 3)

    2. (set! (cons 3 4) (cons 4 5))

    3. (define a 42)
      (set! 'a 10)
      
    4. (define a 42)
      (define (symbol) 'a)
      (set! (symbol) 10)
      
    5. (define a (cons 1 2))
      (set! (car a) 10)
      

    After figuring out what's wrong with them, type them into the Scheme interpreter and see how the interpreter will respond to these "bugs".


Part B: Book Exercises

Please work the following exercises from the textbook:

  1. [30] Exercise 3.2 (encapsulating a function to count number of uses)

  2. [30] Exercise 3.8 (significance of evaluation order)

    HINT: Your function should have some local state variable that gets updated on every function call.

    This shows why having set! in the language makes the evaluation of an expression depend on the order in which operands are evaluated.


Part C: Message-Passing Data Structures with Mutable Objects

[60] The mean and variance are two useful statistical values often computed over a set of numeric data. Without going deeply into what variance is or why it's so important (ask a friend, Google it, wait for Ma2, or go to this page), here are functions to compute each over an input list of numbers:

(define (mean values)   ;; values is a list of numbers
  (/ (apply + values)   ;; sum a list of numbers (note clever use of "apply")
     (length values)))  ;; and divide by the length of the list

(define (variance values)
  (define (square x) (* x x))
  (- (mean (map square values)) ;; subtract the mean of the squares
     (square (mean values))))   ;; from the square of the mean

Often, when collecting data, we receive it one element at a time instead of all at once. It might, then, be useful to be able to determine the mean and variance "on-the-fly" as we add values to the list. (Many scientific calculators let you do this.)

Your job is to create a message-passing statistics object to provide this functionality. Your statistics object should adhere to the following interface:

Note that you shouldn't provide any messages to return the internal list itself -- it should stay internal.

You're allowed to use the definitions of mean and variance given above in your code.

Here are some example interactions with a stat object.

(define mystat (make-stat))
(mystat 'mean)
;; --> error message of some sort
(mystat 'add 1)
(mystat 'add 2)
(mystat 'add 3)
(mystat 'mean)  ;; should --> 2
(mystat 'add 4)
(mystat 'variance)  ;; should --> 5/4