CS 227 Meeting -*- Outline -*- * mutating procedures procedures that mutate some of their arguments like vector-set! will all be given names ending in ! ** multiplying a vector by a scalar in place *** imperative ------------------- MUTATING VEC-MULT-BY-SCALAR! > (define v (vector 1 2 3 4)) > (vec-mult-by-scalar! v 3) > v #(3 6 9 12) vec-mult-by-scalar! : (-> ((vector number) number) void) --------------------- Note that the idea is that v is mutated in place Plan: loop for each element of v, using vector-ref and vector-set! to do it Write this out by hand, following is here just for ref. (define vec-mult-by-scalar! (lambda (v n) (let ((size (vector-length v))) (letrec ((loop! ; TYPE: (-> (natural) void) (lambda (i) ; REQUIRES: i <= size, ; for all 0 <= j < i: ; the jth element of v has ; already been multiplied ; MODIFIES: v ; EFFECT: change elements ; of v to be mult by n, ; starting at i (if (< i size) (begin (vector-set! v i (* (vector-ref v i) n))))))) (loop! 0))))) We use EFFECT to describe side effects informally, instead of ENSURES. Then MODIFIES clause lists what is changed. *** functional -------------------- FUNCTIONAL VEC-MULT-BY-SCALAR (vec-mult-by-scalar (vector 1 2 3 4) 3) ==> #(3 6 9 12) Return a new vector, do not mutate the arg (define vec-mult-by-scalar ; TYPE: (-> ((vector number) number) ; (vector number)) (lambda (v n) ; ENSURES: result is a new vector ; with ith element mutiplied by n (let ((v-copy (vector-copy v))) (vec-mult-by-scalar! v-copy n) v-copy))) -------------------- Q: can you define it using vector-generator? (define vec-mult-by-scalar ; TYPE: (-> ((vector number) number) ; (vector number)) (lambda (v n) ((vector-generator (lambda (i) (* (vector-ref v i) n))) (vector-length v)))) ** reversing the elements of a vector *** imperative ---------------- MUTATING VECTOR-REVERSE! > (define v (vector 1 2 3 4)) > (vector-reverse! v) > v #(4 3 2 1) vector-reverse! : (-> ((vector T)) void) ---------------- It changes its argument (and returns it). ------------------ (define vector-reverse! ;; cf. Prog 9.26 ;TYPE: (-> ((vector T)) void) (lambda (vec) ; MODIFIES: vec ; EFFECT: reverse vec in place (let ((swapv! (swap!-maker vec))) (letrec ((switch! ;: (-> (nat nat ) void) (lambda (i j) ; REQUIRES: 0 <= i <= j ; j <= (vector-length vec), ; positions 0..i and j..length ; have already been swapped (if (< i j) (begin (swapv! i j) (switch! (add1 i) (sub1 j))))))) (switch! 0 (sub1 (vector-length vec)) ))))) (define swap!-maker ;; Prog 9.27 ; TYPE: (-> ((vector T)) ; (-> (natural natural) ; (vector T))) (lambda (vec) (lambda (index1 index2) (let ((temp (vector-ref vec index1))) (vector-update! (vector-update! vec index1 (vector-ref vec index2)) index2 temp))))) -------------------- *** functional The functional version is defferent, returns a new vector, doesn't mutate it's arg. ------------------ (define vector-reverse ; TYPE:(-> ((vector T)) (vector T)) (lambda (vec) (let ((vec-copy (vector-copy vec))) (vector-reverse! vec-copy) vec-copy))) ; Compare Program 9.24 in the text ------------------ Try (let ((a (vector 1 2 3 4 5))) (let ((b (vector-reverse a))) (view a) (view b))) Try some experiments. ** vector-update! This is like vector-set!, but returns the vector. Like vector-update, but mutates its argument. Some consider this bad style, but often used in OOP. ------------------ ; - Program 9.22, pg. 283 - (define vector-update! ; TYPE: (-> ((vector T) natural T) ; (vector T)) (lambda (vec i c) ; REQUIRES: i is a legal index for vec ; MODIFIES: vec ; EFFECT: make the ith element of vec ; be c, and return vec (vector-set! vec i c) vec)) ------------------ try (let ((a (vector 2 4 6))) (let ((b (vector-update! a 1 999))) (writeln a) (writeln b))) and (let ((a (vector 2 4 6))) (let ((b (vector-update a 1 999))) (writeln a) (writeln b))) Repeat remarks about new objects. ** remark interesting to think about abstracting patterns from these.