Lecture 31: Objects and Time

###
Lecture 31: Objects and Time

1. accumulators and contexts

       (f some-large-compound)
       =
       (o stuff1
          (o stuff2
             ... (f some-compound) ...))

   if stuff1, stuff2, ... are needed and/or if the difference between some-large-compound and some-compound is needed, we must use an accumulator

   if we wish to compute several results at once, in one function, we need to use several accumulators

2. the evolution of real-world objects

   We want to simulate a ball as it moves across a table. We first need a data representation for the ball:

       (define-struct ball (coord speed))
       ;; A ball is (make-ball xy delta-xy) where xy and delta-xy are posn's.

       (define sample (make-ball (make-posn 30 20) (make-posn +1 -3)))

   Now we can define a function that simulates the movement:

       ;; move : ball num -> ball
       (define (move a-ball a-time)
         (local ((define delta (ball-speed a-ball)))
           (make-ball (posn+ (posn* a-time delta) (ball-coord a-ball))
                      delta)))

         (move sample 2)
       = (make-ball (make-posn 32 14) (make-posn +1 -3))

   That is, we create a new representation of the ball, every time we simulate a move. But, does the world really create a new ball or do the ball's properties change? In other words, are the two balls intensionally equal even though their coordinates differ?

   If we believe that the ball remains the same, we write an imperative program because it reflects this idea better:

       ;; move! : ball num -> void
       ;; Purpose: -
       ;; Effect: simulate move of a-ball by a-time
       (define (move a-ball a-time)
         (local ((define delta (ball-speed a-ball)))
           (set-ball-coord! a-ball
             (posn+ (posn* a-time delta) (ball-coord a-ball)))))

       (define sample (make-ball (make-posn 32 14) (make-posn +1 -3)))

         (move sample 2)
       = (void) ;;; + change

   Lesson: Use structure modification if the structure represents a real-world object,
   and the function simulates a permanent change.
3. for-each, begin for cons:

   Task: Develop the function `move-all`, which

       ;; move-all : (listof ball) num -> void
       ;; Purpose: -
       ;; Effect: simulates moving lo-balls for a-time
       (define (move-all lo-balls a-time)
         (cond
           ((empty? lo-balls) a-time)
           (else (local ((define dummy (move! (first lo-balls a-time))))
       	    (move-all (rest lo-balls) a-time)))))

   or use `begin`

       ;; move-all : (listof ball) num -> void
       ;; Purpose: -
       ;; Effect: simulates moving lo-balls for a-time
       (define (move-all lo-balls a-time)
         (cond
           ((empty? lo-balls) a-time)
           (else (begin ;; throw away the result of the first expression
       	    (move! (first lo-balls a-time)))
       	    (move-all (rest lo-balls) a-time))))

   the list doesn't change

   Edit the program!

       ;; move-all : (listof ball) num -> void
       ;; Purpose: -
       ;; Effect: simulates moving lo-balls for a-time
       (define (move-all lo-balls a-time)
         (map (lambda (a-ball) (move! a-ball a-time)) lo-balls))

   This is almost correct but it would return (listof void) instead of (void). What to do? Use for-each:

       map      : (X -> Y)    (listof X) -> (listof Y)
       ;; create a list of Y's from a list of X'x by applying a function to each
       ;; of them

       for-each : (X -> void) (listof X) -> void
       ;; modify a list of X's by applying a function to each of them; no result

Matthias Felleisen | This page was generated on Mon Apr 12 15:23:18 CDT 1999.