Lecture 28: Functions are not Elephants





  1. Consider a phone list program:
    A phone-list is either
     * empty
     * (cons pr pl) where
       pr : phone-record
       pl : phone-list
    
    (define-struct phone (name number))
    A phone-record is (make-phone sym num).
    

    Task: develop the following two functions
    ;; lookup : sym phone-list -> number
    ;; Purpose: produce the first number that is 
    ;;  associated with a-name in a-pl 
    ;;  in a phone-record
    (define (lookup a-name a-pl) ...)
    
    ;; update : sym number phone-list -> phone-list
    ;; Purpose: produce a list like a-pl, but with the 
    ;;  first record for name replaced with
    ;;  (make-phone a-name a-number) 
    (define (update a-name a-number a-pl) ...)
    

    How do we "tell" lookup that update produced a new phone list?
    [phone [phone

    The program underneath this GUI looks roughly like this:

    (define PHONE-DB (list ...))
    
    (define (lookup a-name a-pl) ...)
    
    (define (update a-name a-num a-pl) ...)
    
    ;; when someone looks up a phone number, call
      (lookup ...name from window... PHONE-DB) 
    
    ;; when someone updates the phone list, what happens? 
    

    From the user's perspective, the program has "memory". But we know that when we apply lookup to the same name and phone-list twice, we will always get the same number -- no matter how often we have run update. What's up?

  2. set!

    The key to "memory" is that we change what PHONE-DB stands for, i.e., to introduce some notion of time. Here is how that works:

    (set! PHONE-DB
      (update ...name from UI... ...new number from UI...  PHONE-DB))
    

    Let's look at concrete examples:

    (define PHONE-DB
      (list (make-phone 'Bumpy 5554567) (make-phone 'Mickey 6661234)))
    
    > (lookup 'Bumpy PHONE-DB)
    5554567
    > (lookup 'Bumpy PHONE-DB)
    5554567
    > (set! PHONE-DB (update 'Bumpy 3337654))
    > (lookup 'Bumpy PHONE-DB)
    3337654
    
    After a set! to PHONE-DB, the list that PHONE-DB stands for has changed.

    Here is a program that can be associated with an update button on a GUI:

    ;; update! : sym number -> void
    ;; Effect: change what PHONE-DB stands for to (update a-name a-number PHONE-DB)
    (define (update! a-name a-number)
      (set! PHONE-DB (update a-name a-number PHONE-DB)))
    

    Task:Define add!

    ;; add! : sym number -> void
    ;; Effect: adds a phone-record for a-name and a-number to PHONE-DB
    (define (add! a-name a-number)
      (set! PHONE-DB ...))
    


  3. set-phone-name!, set-phone-number!

    instead of modifying what a VARIABLE stands for, we can also change the contents of a record

    (define a-rec (make-phone 'Bumpy 555666))
    
    > (phone-number a-rec) 
    5556666
    > (phone-number a-rec) 
    5556666
    > (set-phone-number! a-rec 5557777)
    > (phone-number a-rec) 
    5557777
    

    Some expressions have an effect only. Similar to routines that draw stuff on the screen. Since we might want to combine those in a sequence, e.g. do do do do, we introduce a new construct:

    (begin expression ... expression)
    This is like and, except that the results of the first few expressions are thrown away. The result of the last one is the result of the entire expression.

    We can define programs now that modify the records on a list:
    ;; update! : symbol number phone-list -> void
    ;; Effect: modify the first record in phone-list 
    ;;   whose name is a-name so that it now contains 
    ;;   a-number
    (define (update! a-name a-number a-pl)
      (cond
        ((empty? a-pl) (void))
        (else (cond 
    	    ((eq? (phone-name (first a-pl)) a-name)
    	     (set-phone-number! (first a-pl) a-number))
    	    (else (update! a-name a-number (rest a-pl)))))))
    
    ;; update : symbol number phone-list -> phone-list
    ;; Purpose:  produce a list like a-pl, but with the 
    ;;  first record for name replaced with
    ;;  (make-phone a-name a-number) 
    (define (update a-name a-number a-pl)
      (cond
        ((empty? a-pl) (void))
        (else (cond 
    	    ((eq? (phone-name (first a-pl)) a-name)
    	     (cons (make-phone (phone-name (first a-pl)) a-number)
    	           (rest a-pl)))
    	    (else
    	     (cons (first a-pl)
    	           (update a-name a-number (rest a-pl))))))))
    
    Compare it with the functional version!





Matthias Felleisen This page was generated on Fri Apr 9 09:17:38 CDT 1999.