CS 227 Lecture -*- Outline -*- be aware of: use of lambda-expressions to describe the vector's mapping * vector-generator and other procedural abstractions of functional style vector-code see section 9.2 of the book ** what it's an abstraction of recall the slides for list->vector, vector-copy recall that vec+ was very similar all had the same plan 1. make a new vector of some length 2. fill in the elements 3. return the new vector -------------------- VECTOR-GENERATOR 1. make a new vector 2. fill in as directed 3. return the new vector --------------------- only thing different was how to fill in the elements It turns out to be convenient to curry this so can use the same way to fill in the elements for different sized vectors -------------------- ((vector-generator (lambda (i) i)) 4) ==> #(0 1 2 3) ; want to be able to define... (define vector-copy (lambda (v) ((vector-generator (lambda (i) (vector-ref v i))) (vector-length v)))) (define vec+ (lambda (v1 v2) ((vector-generator (lambda (i) (+ (vector-ref v1 i) (vector-ref v2 i)))) (vector-length v1)))) vector-generator: (-> ((-> (natural) T)) (-> (natural) (vector T))) ------------------- Note that we've specified only the different part of the procedures as the lambda argument to vector-generator Recall that the value of a vector is a function from indexes to objects this is exactly what is specified here! ------------------ ; - Program 9.21, pg. 283 - (define vector-generator (lambda (gen-proc) (lambda (size) (let ((vec (make-vector size))) (letrec ((loop! ; TYPE: (-> (natural) void) (lambda (i) ; REQUIRES: i <= size ; and for all 0 <= j < i, ; (vector-ref vec j) ; = (gen-proc j) ; MODIFIES: vec ; EFFECT: initialize indexes ; i up to size-1 (if (< i size) (begin (vector-set! vec i (gen-proc i)) (loop! (add1 i))))))) (loop! 0)) vec)))) ------------------ Note that the side effects are hidden from the caller. They are only used internally for inefficiency. Note the loop starts from 0, this make side effects in gen-proc predictable Look carefully at the loop. (Test for last time, no else part, begin.) Note use of EFFECT and MODIFIES ** examples of use *** list->vector ------------------ YOU WRITE (list->vector '()) ==> #() (list->vector '(a b)) ==> #(a b) (list->vector (list 0 1 2 3)) ==> #(0 1 2 3) list->vector : (-> ((list T)) (vector T)) USING vector-generator (and list-ref) ------------------ (define list->vector ;TYPE: (-> (list) vector) (lambda (ls) ; ENSURES: the ith element of result ; is the ith element of ls. ((vector-generator (lambda (i) (list-ref ls i))) (length ls)))) Note this is not as efficient as our earlier version, because of the inefficiency of list-ref... *** vector-map ------------------ (vector-map add1 '#(1 2 3)) ==> #(2 3 4) ; - Program 9.9, pg. 273 - (define vector-map ; TYPE: (-> ((-> (S) T) ((vector S))) ; (vector T)) (lambda (proc vec) ; ENSURES: result is a new vector that ; has ith element proc applied to ; the ith element of vec ((vector-generator (lambda (i) (proc (vector-ref vec i)))) (vector-length vec)))) -------------------- *** vector-apply-elementwise-to-both Like map2, perhaps better called vector-map2... ------------------ ; - Program 9.11, pg. 274 - (define vector-apply-elementwise-to-both ; TYPE: (-> ((-> (S T) U)) ; (-> ((vector S) (vector T)) ; (vector U))) (lambda (proc) ; REQUIRES: the lengths of vec1 ; and vec2 are equal ; ENSURES: result is a new vector that ; has ith element proc applied to ; the ith element of vec1 and vec2 (lambda (vec1 vec2) (let ((gen-proc (lambda (i) (proc (vector-ref vec1 i) (vector-ref vec2 i))))) ((vector-generator gen-proc) (vector-length vec1)))))) Exercise: use this to define vec+ and vec* (vec+ (vector 3 4) (vector 5 6))) ==> #(8 10) ------------------ ** Accumulation *** vector-sum ------------------ (vector-sum (vector )) ==> 0 (vector-sum (vector 3 4 5)) ==> 12 vector-sum: (-> ((vector number)) number) ------------------ Could start at (vector-length vec) and count down. But if order mattered, (i.e., for subtraction), would want to start at i = 0. Also, want to see this pattern, of counting up to size. Q: End test? (= i size) Instead of using sub1, use add1, instead of starting at size, start at 0. ------------------ ; - Program 9.13, pg. 275 - (define vector-sum (lambda (vec) ; ENSURES: result is the sum of ; the numbers in vec (let ((size (vector-length vec))) (letrec ((helper (lambda (i) (if (= i size) 0 (+ (vector-ref vec i) (helper (add1 i))))))) (helper 0))))) Exercise: write vector-product. (vector-product (vector )) ==> 1 (vector-product (vector 3 4 5)) ==> 60 ------------------ replace 0 by 1, + by * **** Abstraction These are very similar. Can abstract out the common parts (like reduce). ------------------ ; - Program 9.15, pg. 277 - (define vector-accumulate ;TYPE: (-> ((-> (S T) T) T) ; (-> ((vector S)) (vector T))) (lambda (proc seed) (lambda (vec) (let ((size (vector-length vec))) (letrec ((helper ; TYPE: (-> (nat) (vector T)) (lambda (i) (if (= i size) seed (proc (vector-ref vec i) (helper (add1 i))))))) (helper 0)))))) Exercise: Use this to define vector->list (vector->list (vector 'next 'please)) ==> (next please) ------------------ see program 9.16 for the answer