Pragmatics of set! When using set!, you might want to reflect on which of these purposes you're using it for. And if not any of these, you might want to reflect on whether your program needs set!, and if the structure of the code might better match the structure of the data if you use one of the templates (structure, w/ accumulator, generative). Don't forget everything you've learned previously!

Sharing state between several functions:
;;;;;;;;;;;;;;;;;;;
(define directory empty)

(define-struct entry (name number))

;; add-entry!: symbol number --> list-of-entries
;; SIDE-EFFECT: add a new entry to direcotry.
;; We return (the updated) directory.
;;   (Not necessary to return this, since anybody can
;;   look up the placeholder "directory" at any time,
;;   to get that same info.)
;;
;;   However, a useful rule of thumb: when writing a function
;;   which modifies an object but doesn't otherwise return
;;   an interesting value, have it return the object being modified.
;;   This is often convenient in allowing you to pass that
;;   value to the next function, w/o having to use "begin".
;;
(define (add-entry! name number)
  (begin
    (set! directory (cons (make-entry name number) directory))
    directory))

;; lookup: symbol --> entry or false
;;
(define (lookup name)
  (lookup-helper name directory))

;; lookup-helper: symbol, list-of-entries --> entry or false
(define (lookup-helper name entries)
  (cond [(empty? entries) false]
        [(cons?  entries) (if (symbol=? (entry-name (first entries)) name)
                              (first entries)
                              (lookup-helper name (rest entries)))]))
There is one big problem with this: the directory is public to everybody, and other programmers might (inadvertently) change the directory directly. And perhaps incorrectly, even if they're smart people: maybe your add-entry! prohibits duplicate entries, and your lookup relies on this fact, but somebody else didn't realize this and bypassed your add-entry!!

Another example:
A random-number generator:

(define seed 0)
;; return a pseudo-random int in [0,100)
(define (rand)
  (begin (set! seed (next-num seed))
         seed))

;; next-num: number --> number
;; Return the next number in an (ahem) random sequence.
;;
(define (next-num n)
  (remainder (+ 17 (* n 41)) 100))
Calling (rand) repeatedly yields: This yields the sequence 17, 14, 91, 48, 85, ...
Must this repeat? A bit of thinking shows that it must, with a cycle of length 100 (or possibly less?). (NB if i change 41 to 43, i get 17,48,81,0,17,... -- oops, repeating very soon!)

Of course, the limit 100 could be made more flexible: How could we make it so ? (define max-rand 100)


(b) An alternative use: keep track of history. You are disgruntled, about to quit, and you write code that will stop working after 100 times (just returning 'haha instead of answer). Version I:

  (define times-called 0)
  (define select-by-color
    (lambda (kroma)
       (begin (set! times-called (add1 times-called))
              (if (> times-called 100)
                  'haha
                  ...the real code...))))


Version II: We don't want the placeholder to be global. Move it inside the define, before the lambda.
Question: does this make a new copy of the placeholder every time select-by-color is called? Or just one placeholder? (Clearly, we *want* the latter.)

To answer, remember the law-of-scheme, the semantics of "define". In particular, Cf. (define x (+ 3 4)) Is + called every time x is used, or just once? Answer: The way define works, just once. In our case "local" is analagous to "+". It is only called once, it returns a value (a lambda involving times-called%473), and referring to the placeholder just looks up this lambda. The *local* is evaluated only once.

What if we'd put the local inside the lambda? *Then* every time we call the function, the local is evaluated, making a new placeholder: Cf. (define function-x (lambda () (+ 3 4))) Now, every time function-x is called, the + is evaluted.


[not mentioned:
When is an example when we might want indeed to have the local be insdie the lambda, to create a local var many times? Probably when the value returned is a function and each function returned wants to use its own local variable (alternative: all functions returned refer to the same variable.) What is wrong with the following?

(define make-shopper-card
  (local [(define most-recently-bought #f)]
    (lambda (name)
       (lambda (command some-item)
          (cond [(eq? command 'show-name) name]
                [(eq? command 'buy) (set! most-recently-bought some-item)]
                [(eq? command 'show-fave) most-recently-bought])))))
How to fix it?


(c) Imperative programming:
In scheme, the fundamental unit of computation is function-call. (A functional language)
In imperative langauges (JAM, C, Java), the fundamental unit is assign-to-variable (and sequence), with a background emphasis on calling functions.


The complete code from lecture:
;;;;;;;;;;;;;;;;;;;
(define directory empty)

(define-struct entry (name number))

;; add-entry!: symbol number --> list-of-entries
;; SIDE-EFFECT: add a new entry to direcotry.
;; We return (the updated) directory.
;;   (Not necessary to return this, since anybody can
;;   look up the placeholder "directory" at any time,
;;   to get that same info.)
;;
;;   However, a useful rule of thumb: when writing a function
;;   which modifies an object but doesn't otherwise return
;;   an interesting value, have it return the object being modified.
;;   This is often convenient in allowing you to pass that
;;   value to the next function, w/o having to use "begin".
;;
(define (add-entry! name number)
  (begin
    (set! directory (cons (make-entry name number) directory))
    directory))

(define (lookup name)
  (lookup-helper name directory))

(define (lookup-helper name entries)
  (cond [(empty? entries) false]
        [(cons?  entries) (if (symbol=? (entry-name (first entries)) name)
                              (first entries)
                              (lookup-helper name (rest entries)))]))





;;;;;;;;;;;;;;;;;;;

(define seed 0)
;; return a pseudo-random int in [0,100)
(define (rand)
  (begin (set! seed (next-num seed))
         seed))

;; next-num: number --> number
;; Return the next number in an (ahem) random sequence.
;;
(define (next-num n)
  (remainder (+ 17 (* n 41)) 100))




;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; Use #3 of set!: communicating values between distant parts of programs.

; A flag: is the program done?
;
(define ready-to-leave false)

(define (do-look) "Looking around ...")
(define (quit)  (begin (set! ready-to-leave true)
                       "Good-bye."))

(define (unknown) "huh?")

(define commands (list (list 'look do-look)
                       (list 'q    quit)))

(define (spelunk dummy-input)
    (cond [ready-to-leave   (void)]
          [else (let* {[_ (printf "What now? ")]
                       [the-command-pair (assoc (read) commands)]
                       [the-command      
                        (if (list? the-command-pair) 
                            (second the-command-pair)
                            unknown)]}

                  (spelunk (printf (string-append (the-command) "~n"))))]))