590 likes | 605 Views
Learn about the use of local variables in programming and how they can improve the efficiency of your code. Explore examples and understand when to use local variables.
E N D
TeachScheme, ReachJava Adelphi University Wednesday afternoon June 24, 2008
New topic: Local variables Recall largest function. Try it on(list 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1) and on(list 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20) Why is one so slow? (depending on how you wrote it) Use Stepper to see
Local variables Problem: recomputing recursive call. Solution: Call once, use result twice. One way: use helper functionlarger : number number -> number Another way: define local variable to hold result, then use variable twice.
Local variables Switch languages to “Intermediate Student” Syntax rule: (local [(define var expr) (define var expr) …]expr) Defines the variables for just long enough to evaluate the final expr. (local [(define x 3) (define y 5)] (* x y)) ; returns 15, but x and y are undefined afterwards
distance with locals ; distance : posn posn -> number (define (distance here there) (sqrt (+ (sqr (- (posn-x here) (posn-x there))) (sqr (- (posn-y here) (posn-y there))))))
distance with locals ; distance : posn posn -> number (define (distance here there)(local [(define xdiff (- (posn-x here) (posn-x there))) (define ydiff (- (posn-y here) (posn-y there)))] (sqrt (+ (sqr xdiff) (sqr ydiff))))) Actually somewhat longer, but arguably easier to understand because intermediate values have names
largest with locals (define (largest nums)(cond [(empty? (rest nums)) (first nums)] [(cons? (rest nums))(local [(define maxrest (largest (rest nums)))] (cond [(>= (first nums) maxrest) (first nums)] [else maxrest]) )]))
When to use locals • to give names to important intermediate values • to avoid recomputing expensive expressions (especially recursive ones) • to define things that are only of interest within a particular function(Note: can also define functions & structs inside a local!)
New topic: Natural numbers A natural number is either definition by choices!0, or(+ 1 natural-number) definition by (recursive) part! Examples: 0, (+ 1 0), (+ 1 (+ 1 0)), etc. We use the names 0, 1, 2, etc. for short. To get the previous natural-number from a non-zero natural-number n, use (- n 1)
Natural numbers #| (check-expect (function-on-natural 0) …) (check-expect (function-on-natural 1) …) (check-expect (function-on-natural 5) …) (define (function-on-natural n)(cond [(= n 0) …] [else ; n non-zero natural number ; (- n 1) natural number ; (function-on-natural (- n 1)) … …)) |#
Natural numbers Example: count-down : natural -> list-of-numbers (check-expect (count-down 0) (list 0)) (check-expect (count-down 1) (list 1 0)) (check-expect (count-down 5) (list 5 4 3 2 1 0))
Natural numbers (define (count-down n)(cond [(= n 0) …] [else ; n non-zero natural ; (- n 1) natural ; (count-down (- n 1)) list of nums …))
Natural numbers (define (count-down n)(cond [(= n 0) …] [else ; n non-zero natural 5 ; (- n 1) natural 4 ; (count-down (- n 1)) list of nums (list 4 3 2 1 0); should be list of nums (list 5 4 3 2 1 0) …))
Natural numbers (define (count-down n)(cond [(= n 0) (list 0)] [else ; n non-zero natural 5 ; (- n 1) natural 4 ; (count-down (- n 1)) list of nums (list 4 3 2 1 0) ; should be list of nums (list 5 4 3 2 1 0)(cons n (count-down (- n 1)))))
Exercises Define a function sqr-table which takes in a natural number and produces a list of posns, each containing a number and its square. The x coordinates should go from the given number down to 1, inclusive. For example, (sqr-table 4) should be (list (make-posn 4 16) (make-posn 3 9) (make-posn 2 4) (make-posn 1 1))
Exercises • Define a function row-of-dots which takes in a natural number and produces a picture of that many radius-10 orange dots side by side. • Define a function orange-pile which takes in a natural number and produces a picture like
New topic: Abstracting functions Consider… • add-1-to-each : list-of-numbers -> list-of-numbers • cube-each : list-of-numbers -> list-of-numbers • animal-weights : list-of-animals -> list-of-numbers • convert-grades : list-of-numbers -> list-of-strings • substitute : string string list-of-strings -> list-of-strings • give-10%-raises : list-of-emps -> list-of-emps All take in a list, do some operation to each element of it, & return a list of the results. All have almost identical code, differing only in the operation.
Abstracting functions When several functions have similar code, differing in one thing, turn that thing into a parameter. ; do-to-each : operation list -> list More precisely, ; do-to-each : (X->Y) list-of-X -> list-of-Y where X and Y are any data types (Requires Intermediate Student language) Work this out together Predefined version is named map
Abstracting functions Consider… • count-elements • count-over-100 • count-earning-over-100k • count-tigers All take in a list and return how many elements meet a certain criterion. General version: ; count-if : test list -> number More precisely, ; count-if : (X->boolean) list-of-X -> number
Abstracting functions Consider… • remove-evens • fire-over-100k • keep-positives • extract-fish All take in a list and extract from it the elements that meet a certain criterion General version: ; filter : test list -> list More precisely, ; filter : (X->boolean) list-of-X -> list-of-X Predefined, but we could have written it easily
Abstracting functions Consider… • add-up • multiply-up • total-salary • any-over-100? • sort All take in a list and combine its elements, starting from the empty and mixing in one more element at a time. They differ in the answer to the empty case, and in how they combine things. General form: ; foldr : (X Y->Y) Y list-of-X -> Y (predefined, but we could have…) (define (add-up L) (foldr + 0 L)) (define (any-over-100? L) (foldr or false L))
Exercises • Write a function remove-if that takes a function X->boolean and a list of X's, and returns a list of the X's on which the function returns false. • Write a function fire-over-100k that takes a list of employees and removes all those who earn over $100,000. No recursion!
Functions on the Fly • Calling a function like map, count-if, filter, or foldr often requires making up a function just to pass in — otherwise useless. • Example:(define (add-3-to-each nums) (map add3 nums))(define (add3 x) (+ x 3) • This is silly.
Functions on the Fly: local • Example:(define (add-3-to-each nums)(local [(define (add3 x) (+ x 3))] (map add3 nums))) • add3 is "hidden" inside add-3-to-each; doesn't "pollute" rest of world.
Functions on the Fly: lambda • Switch languages to “Intermediate Student with Lambda” • Syntax rule:(lambda (params) expr)is a (nameless) function that takes in values for the params and evaluates the expr • Example:(define (add-3-to-each nums) (map (lambda (x) (+ x 3)) nums))) • add3 isn't even named.
Functions on the Fly • More natural example; add-to-each : number list-of-numbers -> list-of-numbers • Can't do this with a separate function, because we don't know what it's supposed to add until add-to-each is called. • Easy to do with either local or lambda. • (define (add-to-each num nums)(local [(define (addit x) (+ x num))] (map addit nums))) • (define (add-to-each num nums) (map (lambda (x) (+ x num)) nums))
Exercises • Write a function fire-over that takes a number and a list of employees, and removes all the ones who earn over that much money. Use local or lambda.
Functions returning functions • Suppose we had lots of occasions to produce a function like add3 or add17. • Can do it each time with local or lambda, or… • … automate it with a function! Then… • (define (add-to-each num nums) (map (make-adder num) nums))
Functions returning functions ; make-adder : num -> (num -> num) (check-expect ((make-adder 3) 4) 7) (check-expect ((make-adder -6) 29) 23) (check-expect (map (make-adder 2) (list 3 4 5)) (list 5 6 7)) (define (make-adder to-add)(local [(define (f x) (+ x to-add))] f))
Functions returning functions ; make-adder : num -> (num -> num) (check-expect ((make-adder 3) 4) 7) (check-expect ((make-adder -6) 29) 23) (check-expect (map (make-adder 2) (list 3 4 5)) (list 5 6 7)) (define (make-adder to-add)(lambda (x) (+ x to-add)))
Extra credit exercises • Define a function twice that takes in a function f:X->X and returns the function g(x) = f(f(x)). For example,(define add2 (twice add1))(define 4th-root (twice sqrt)) • Define a function iterate that takes in a function f:X->X and a natural number n and returns the function f(n), i.e. f composed with itself n times. For example,(define add5 (iterate add1 5))
Abstracting functions I try to introduce this stuff in Scheme because • it's a powerful programming tool in any language • it's enormously easier in Scheme than in C++ or Java • it blows people's minds
Family trees, version 1 A person has a string(name), number(birth-year), string(eye-color), mother, and father. What types are mother and father? Obviously, "person". So let's go through the design recipe… (define-struct person (name birth-year eye-color mother father))
Family trees, version 1 ; Contracts for functions that come "for free": ; make-person : string num string person person -> person ; person-name : person -> string ; person-birth-year : person -> number ; person-eye-color : person -> string ; person-mother : person -> person ; person-father : person -> person
Family trees, version 1 ; Examples of the data type: (make-person "Fred" 1924 "brown" ? ?) In order to create a person we need to already have two other persons. Problem! In addition, in any real family tree, you eventually run out of information and have to say "unknown".
Family trees, version 2 A person has a string(name), number(birth-year), string(eye-color), mother, and father. What types are mother and father? "family tree", or "ftree" for short. An ftree is either unknown or a person.
Family trees, version 2 A person has a string(name), number(birth-year), string(eye-color), mother, and father. What types are mother and father? "family tree", or "ftree" for short. An ftree is either unknown or a person.
Family trees, version 2 (define-struct person (name birth-year eye-color mother father)) ; make-person : string num string ftree ftree -> person ; person-name : person -> string ; person-birth-year : person -> number ; person-eye-color : person -> string ; person-mother : person -> ftree ; person-father : person -> ftree ; person? : anything -> boolean (define-struct unknown ()) ; make-unknown : nothing -> unknown ; unknown? : anything -> boolean
Family trees, version 2 ; Examples of data types (define unk (make-unknown)) ; is an unknown, and therefore an ftree (define fred (make-person "Fred" 1924 "brown" unk unk); is a person (define mary (make-person "Mary" 1922 "green" unk unk)) (define anne (make-person "Anne" 1944 "blue" mary fred)) (define bob (make-person "Bob" 1939 "blue" unk unk)) (define phil (make-person "Phil" 1966 "hazel" anne bob))
Family trees, version 2 (define (function-on-person p); p a person; (person-name p) a string; (person-birth-year p) a number; (person-eye-color p) a string; (person-mother p) an ftree; (function-on-ftree (person-mother p)) whatever; (person-father p) an ftree; (function-on-ftree (person-father p)) whatever) (define (function-on-ftree ft); ft an ftree, i.e. person or unknown(cond [(unknown? ft) ; base case ] [(person? ft) (function-on-person ft)]))
Family trees, version 2 Or we could collapse the two into one big function: (define (function-on-ftree ft); ft an ftree, i.e. person or unknown(cond [(unknown? ft) ; base case ] [(person? ft) ; ft a person ; (person-name ft) a string ; (person-birth-year ft) a number ; (person-eye-color ft) a string ; (person-mother ft) an ftree ; (function-on-ftree (person-mother ft)) whatever ; (person-father p) an ftree ; (function-on-ftree (person-father ft)) whatever ]))
Writing functions on ftrees & persons Write a function count-people which takes in an ftree & returns how many persons are in it ; count-people : ftree -> number ; Data analysis: already done ; Can write either as two mutually recursive functions, or as one recursive function
Writing functions on ftrees & persons (check-expect (count-people unk) 0) (check-expect (count-people fred) 1) (check-expect (count-people anne) 3) (check-expect (count-people phil) 5)
Writing functions on ftrees & persons (define (function-on-person p); p a person; (person-name p) a string; (person-birth-year p) a number; (person-eye-color p) a string; (person-mother p) an ftree; (function-on-ftree (person-mother p)) whatever; (person-father p) an ftree; (function-on-ftree (person-father p)) whatever) (define (function-on-ftree ft); ft an ftree, i.e. person or unknown(cond [(unknown? ft) ; base case ] [(person? ft) (function-on-person ft)]))
Writing functions on ftrees & persons (define (count-people-person p); p a person; (count-people (person-mother p)) number; (count-people (person-father p)) number) (define (count-people ft); ft an ftree, i.e. person or unknown(cond [(unknown? ft)0 ] [(person? ft) (count-people-person ft)]))
Writing functions on ftrees & persons (define (count-people-person p); p a person; (count-people (person-mother p)) number; (count-people (person-father p)) number(+ 1 (count-people (person-mother p)) (count-people (person-father p)))) (define (count-people ft); ft an ftree, i.e. person or unknown(cond [(unknown? ft)0 ] [(person? ft) (count-people-person ft)]))
Writing functions on ftrees & persons Or, collapsing the two into one big function,… (define (function-on-ftree ft); ft an ftree, i.e. person or unknown(cond [(unknown? ft) ; base case ] [(person? ft) ; ft a person ; (person-name ft) a string ; (person-birth-year ft) a number ; (person-eye-color ft) a string ; (person-mother ft) an ftree ; (function-on-ftree (person-mother ft)) whatever ; (person-father p) an ftree ; (function-on-ftree (person-father ft)) whatever ]))
Writing functions on ftrees & persons Or, collapsing the two into one big function,… (define (count-people ft); ft an ftree, i.e. person or unknown(cond [(unknown? ft)0 ] [(person? ft) ; ft a person ; (person-name ft) a string ; (person-birth-year ft) a number ; (person-eye-color ft) a string ; (person-mother ft) an ftree ; (count-people (person-mother ft)) number ; (person-father p) an ftree ; (count-people (person-father ft)) number ]))
Writing functions on ftrees & persons Or, collapsing the two into one big function,… (define (count-people ft); ft an ftree, i.e. person or unknown(cond [(unknown? ft) 0 ] [(person? ft) ; (count-people (person-mother ft)) number ; (count-people (person-father ft)) number (+ 1 (count-people (person-mother ft)) (count-people (person-father ft))) ]))