Download presentation
Presentation is loading. Please wait.
Published byKristian Watkins Modified over 8 years ago
1
Lecture on Set! And Local CS 2135 Copyright Kathi Fisler, 2002 This material requires Advanced Language Level
2
Motivating Example Consider an on-line address book. The address book provides two features: you can search it for a particular person's phone number, or you can add a new person and phone number to the address book. We'll use symbols for names and numbers for phone numbers (ignore dashes). Thus, we need to write two functions: ;; lookup-number : symbol (number or false) ;; returns number stored for person in phone book, or false ;; if no number for that person in the phone book (define (lookup-number name)...) ;; add-to-address-book : symbol number true ;; updates address book with number for given name (define (add-to-address-book name phone)...)
3
Motivating Example After we add someone to the book, we should be able to look them up: > (lookup-number 'Kathi) [returns false] > (add-to-address-book 'Kathi 1234567) [returns true] > (lookup-number 'Kathi) [returns 1234567] ;; lookup-number : symbol (number or false) ;; returns number stored for person in phone book, or false ;; if no number for that person in the phone book (define (lookup-number name)...) ;; add-to-address-book : symbol number true ;; updates address book with number for given name (define (add-to-address-book name phone)...)
4
Motivating Example After we add someone to the book, we should be able to look them up: > (lookup-number 'Kathi) [returns false] > (add-to-address-book 'Kathi 1234567) [returns true] > (lookup-number 'Kathi) [returns 1234567] This is rather different behavior than we’re used to: normally, if you call a function twice with the same arguments, you get the same answer each time. Here, we need to get different answers from the two uses of (lookup-number ‘Kathi) We’re going to need some new Scheme construct to implement this. We’ll also need variables whose value can change over time
5
Defining the Address Book Whenever we define a variable whose value we expect to change, we should provide a statement (like a contract) indicating its type and what it contains. ;; An entry is a ;; (make-entry symbol number) (define-struct entry (name number)) ;; address-book : list[entry] ;; keep track of the current address book entries (define address-book empty) We call variables such as address-book state variables, because they capture (and remember) the state of the program at some moment in time.
6
Add-Address-Book ;; add-to-address-book : symbol number -> true ;; purpose : updates address book with number for given name ;; effect : changes the value of address-book to include entry for name (define (add-to-address-book name num) (begin (set! address-book (cons (make-entry name num) address- book)) true)) Once we write programs that change the values of variables, we should document what those changes will be. We therefore add an effect comment to any program that changes the value of a variable.
7
Add-Address-Book ;; add-to-address-book : symbol number -> true ;; purpose : updates address book with number for given name ;; effect : changes the value of address-book to include entry for name (define (add-to-address-book name num) (begin (set! address-book (cons (make-entry name num) address- book)) true)) Once we write programs that change the values of variables, we should document what those changes will be. We therefore add an effect comment to any program that changes the value of a variable. This code also introduces a new keyword, set!. Set! is Scheme's assignment operator.
8
Set! A set! expression requires two pieces of information: a variable and an expression: (set! var some-exp) As with all expressions, DrScheme evaluates some-exp first, then changes the value of var to the value of some- exp. A set! expression has (returns) an invisible value. It has a visible effect though, because the old definition of var gets erased and replaced with the value of some-exp.
9
Set! Consider the following program: (define n 5) (begin (set! n (+ n 1)) n) Obviously, this should (and does) return 6. How does Scheme evaluate it? Evaluate the set! by replacing the value of n
10
Set! Consider the following program: (define n 6) (begin n) Evaluate the set! by replacing the value of n also take out the (set! …) because we’ve finished it Now, evaluate the n, which returns the 6. set! effectively replaces the old define with a new one -- There’s no way to recover the old definition
11
Another Example (define x 4) (define y 4) (define x 4) (define y 4) (begin (set! y x)) (define x 3) (define y 4) (begin (set! x y) (set! y x)) Eval (set! x y)Eval (set! y x) This code does not swap the values of x and y
12
Another Try at Swap (define u 4) (define v 5) (let ([tmp 4]) (set! x 5) (set! y tmp))) (define u 4) (define v 5) (define (swap x y) (let ([tmp x]) (set! x y) (set! y tmp))) (swap 4 5) (define u 4) (define v 5) (define (swap x y) (let ([tmp x]) (set! x y) (set! y tmp))) (swap u v) Subst 4 and 5 for u and v Eval (swap 4 5) You cannot write a swap function in Scheme using set! Code doesn’t affect u or v
13
The Only Way to Swap with Set! (define x 4) (define y 5) (define tmp x) (define x y) (define y tmp) But this relies on global variables, which we won’t be using (luckily, you won’t need to write swap code either!)
14
Introducing Local Local provides a means for defining local variables. It is more powerful than let (in ways that aren't important at the moment). Here's an example that uses two definitions: (define (expt5 x) (local [(define (square y) (* y y)) (define (cube z) (* z (square z)))] (* (square x) (cube x)))) (expt5 2) yields 32, as expected (cube 3) yields an error – the definition is not visible outside expt5
15
Evaluating Local (define (expt5 x) (local [(define (square y) (* y y)) (define (cube z) (* z (square z)))] (* (square x) (cube x)))) First step is just a normal function call: (expt5 2) (local [(define (square y) (* y y)) (define (cube z) (* z (square z)))] (* (square 2) (cube 2)))) Now, DrScheme copies the defines as if you put them in the definitions window, but it gives the functions dummy names (so they remain invisible outside of the scope of expt5)
16
Evaluating Local (local [(define (square y) (* y y)) (define (cube z) (* z (square z)))] (* (square 2) (cube 2)))) Now, DrScheme copies the defines as if you put them in the definitions window, but it gives the functions dummy names (so they remain invisible outside of the scope of expt5) (define (dummy-square y) (* y y)) (define (dummy-cube z) (* z (square z))) (* (dummy-square 2) (dummy-cube 2)) From here, evaluation proceeds as usual in Scheme
17
Evaluating Local (local [(define (square y) (* y y)) (define (cube z) (* z (square z)))] (* (square 2) (cube 2)))) You won’t see any of these changes to dummy names in your code or in DrScheme. All of this goes on behind the scenes (define (dummy-square y) (* y y)) (define (dummy-cube z) (* z (square z))) (* (dummy-square 2) (dummy-cube 2))
18
Summarizing Local...top-level definitions... (local (defs) body) becomes:...top-level definitions......defs... (renamed for uniqueness) body (with renaming)
19
Returning to the Address Book (define (lookup-number name) (local [(define matches (filter (lambda (an-entry) (symbol=? name (entry-name an-entry))) address-book))] (cond [(empty? matches) false] [else (entry-number (first matches))]))) ;; lookup-number : symbol (number or false) ;; returns number stored for name in address book or false if no number Write lookup-number using local and filter Assume from earlier: (define-struct entry (name number)) (define address-book empty) [updated with add-address]
20
When to Use Set! Use set! when you have to implement more than one service on a data structure and one service must modify the data structure Warning: any uses of set! in your code (homeworks, etc) must be justifiable using one of the situation we cover in this lecture. We’ll deduct points for random or unnecessary uses of set! Why? Because a vast portion of programming can be done without assignment, and we want to you know when it’s needed and when not
21
Another Example: Traffic Lights Assume we had a simple program to produce the light colors for a traffic light (in sequence). We’d expect this to operate as: > (next-light) ‘green > (next-light) ‘yellow > (next-light) ‘red How can we write the next-light program? [Try it] Notice next-light is a function that takes no arguments … This function produces different answers, even when called the same way. The result depends on some previous result
22
Next-light, a first implementation ;; curr-color : one of 'red, 'green, or 'yellow ;; stores the current color of the traffic light (define curr-color 'red) ;; next-light : 'red, 'green, or 'yellow ;; effect : changes curr-color to reflect the next color of the light (define (next-light) (local [(define next-color (cond [(symbol=? curr-color 'red) 'green] [(symbol=? curr-color 'yellow) 'red] [(symbol=? curr-color 'green) 'yellow]))] (begin (set! curr-color next-color) curr-color))) Hint: Start with a variable for the color
23
A Big-Picture Issue Assume you've been running the address book program for several weeks and have built up a large list of numbers. Your roommate asks to use your computer, and starts writing a program as follows: (define address-book empty)... What's now happened to your address book? It's gone. Destroyed. Since set! changes variable values, you've lost your entire address book. Once you have set!, you need to protect variables by not defining them at top level (i.e., no global variables!)
24
A New Set! Rule Only use set! on variables declared in a local Our traffic light program violated this rule, because curr- color was a global variable. We need to make it a variable in a local in order to set! it …
25
Next-light, hiding the variable ;; next-light : 'red, 'green, or 'yellow ;; effect : changes curr-color to reflect the next color of the light (define (next-light) ;; curr-color : one of 'red, 'green, or 'yellow ;; stores the current color of the traffic light (local [(define curr-color 'red) (define next-color (cond [(symbol=? curr-color 'red) 'green] [(symbol=? curr-color 'yellow) 'red] [(symbol=? curr-color 'green) 'yellow]))] (begin (set! curr-color next-color) curr-color))) Run next-light 3 times. What answers do you get? You get ‘green all three times, instead of seeing it change. Why??
26
Next-light, hiding the variable ;; next-light : 'red, 'green, or 'yellow ;; effect : changes curr-color to reflect the next color of the light (define (next-light) ;; curr-color : one of 'red, 'green, or 'yellow ;; stores the current color of the traffic light (local [(define curr-color 'red) (define next-color (cond [(symbol=? curr-color 'red) 'green] [(symbol=? curr-color 'yellow) 'red] [(symbol=? curr-color 'green) 'yellow]))] (begin (set! curr-color next-color) curr-color))) Run next-light 3 times. What answers do you get? Remember how local works – curr-color is renamed to a new dummy variable every time you call next-light
27
How do we fix the traffic light? Think about it – where could we define curr-color to avoid it getting redefined every time? We’ll go over the solution in the next class …
Similar presentations
© 2024 SlidePlayer.com. Inc.
All rights reserved.