![]() |
![]() |
|
home—lectures—exams—hws—breeze (snow day)
1 #lang racket 2 3 4 ; NOTE: you must use #lang racket ('language: as determined in source') 5 ; rather than advanced-student, to get the var-args syntax: 6 (define (test-language-level a b . otherArgs) 7 (length otherArgs)) 8 9 10 11 ;;; We implement a random-number generator. 12 ;;; We need state to do this; 13 ;;; version 1 will use (and set!) a global variable `seed`. 14 ;;; 15 16 (define seed 1) 17 (define MAX-RAND 123) 18 19 (define (next-rand-v1) 20 (begin (set! seed (remainder (+ (* 23 seed) 17) MAX-RAND)) 21 seed)) 22 23 (define (set-seed!-v1 new-val) 24 (set! seed new-val)) 25 26 27 28 "v1:" 29 (next-rand-v1) 30 (next-rand-v1) 31 (next-rand-v1) 32 (next-rand-v1) 33 (next-rand-v1) 34 "re-setting v1:" 35 (set-seed!-v1 1) 36 (next-rand-v1) 37 (next-rand-v1) 38 39 40 ;;;;;;;;;;;;;;;; 41 ;; v1 is nice, but it has a major problem: 42 ;; since 'seed' is global, anybody can muss with that variable. 43 44 45 ;; v2: a version where `seed` is 'private'. 46 47 (define two-rng-funcs 48 (let* {[seed 1] 49 [MAX-RAND 123] 50 [next-rand (lambda () 51 (begin (set! seed (remainder (+ (* 23 seed) 17) MAX-RAND)) 52 seed))] 53 [set-seed! (lambda (new-val) (set! seed new-val))]} 54 (list next-rand set-seed!))) 55 56 (define next-rand-v2 (first two-rng-funcs)) 57 (define set-seed!-v2 (second two-rng-funcs)) 58 ;;; Note: the above is common enough that scheme provides 'match-define': 59 ;;; (match-define (list next-rand-v2 set-seed!-v2) two-rng-funcs) 60 ;;; 61 ;;; In python: (x,y) = (3,4) 62 ;;; (nextRandv2, setSeedv2) = two-rng-funcs 63 64 65 ;;; DEFINITION: the "closure" of a function is the set of all 66 ;;; binding which the function can refer to. 67 ;;; Note that at the top-level, 68 ;;; the id `next-rand-v2` is in scope, 69 ;;; the id `seed` is not in scope, 70 ;;; but it *is* in the function's scope. 71 ;;; (Put another way: even though we finished eval'ing the let* 72 ;;; a long time ago, the variable it created might live on inside 73 ;;; a function's closure, so it can't be garbage collected. 74 ;;; Hopefully such variables were allocated on the heap, 75 ;;; not on the stack!) 76 77 78 "v2:" 79 (next-rand-v2) 80 (next-rand-v2) 81 (next-rand-v2) 82 (set-seed!-v2 1) 83 (next-rand-v2) 84 (next-rand-v2) 85 86 87 88 ;;;;;;;;;;;;;; 89 ;; A version where we can make 90 ;; *multiple* pairs-of-functions-which-each-share-a-local-`seed`. 91 92 93 (define (rng-factory) 94 (let* {[sseed 1] 95 [MAX-RAND 123] 96 [next-rand (lambda () 97 (begin (set! sseed (remainder (+ (* 23 sseed) 17) MAX-RAND)) 98 sseed))] 99 [set-seed! (lambda (new-val) (set! sseed new-val))]} 100 (list next-rand set-seed!))) 101 102 ;; The only difference in code between v2 and v3: 103 ;; the parens around 'rng-factory'! 104 105 106 (match-define (list next-rand-v3a set-seed!-v3a) (rng-factory)) 107 (match-define (list next-rand-v3b set-seed!-v3b) (rng-factory)) 108 109 110 111 "v3a:" 112 (next-rand-v3a) 113 (next-rand-v3a) 114 (next-rand-v3a) 115 (set-seed!-v3a 1) 116 (next-rand-v3a) 117 "v3b:" 118 (next-rand-v3b) 119 (next-rand-v3b) 120 (next-rand-v3b) 121 (set-seed!-v3b 1) 122 (next-rand-v3b) 123 (next-rand-v3b) 124 125 "continue using next-rand-v3a" 126 (next-rand-v3a) 127 (next-rand-v3a) 128 129 130 ;;;;;;;;;;;;;;;;;; 131 ;; A version where instead of returning a list-of-functions, 132 ;; we return one "meta function" which dispatches to the 133 ;; function that is being asked for: 134 ;; 135 (define (new-rng) 136 (let* {[sseed 1] 137 [MAX-RAND 123] 138 [next-rand (lambda () 139 (begin (set! sseed (remainder (+ (* 23 sseed) 17) MAX-RAND)) 140 sseed))] 141 [set-seed! (lambda (new-val) (set! sseed new-val))] 142 } 143 (lambda (msg . other-args) 144 (cond [(symbol=? msg 'next) (apply next-rand other-args)] 145 [(symbol=? msg 'seed!) (apply set-seed! other-args)] 146 [else (error 'rng (format "No such method recognized: ~a" msg))])))) 147 148 149 150 151 "v4a: (objects)" 152 (define r (new-rng)) 153 (define s (new-rng)) 154 (r 'next) 155 (r 'next) 156 (r 'next) 157 (r 'seed! 1) 158 (r 'next) 159 (r 'next) 160 "v4b:" 161 (s 'next) 162 (s 'next) 163 (s 'next) 164 (s 'seed! 1) 165 (s 'next) 166 (s 'next) 167 168 169 170 ;;;;;;;;;;;;;;;; 171 ;;; A sub-class: 172 ;;; "class niftier-rng extends rng": 173 ;;; 174 ;;; We add a new method 'skip' (which advances the seed, but returns nothing useful), 175 ;;; and we override 'next' so that it doubles the superclass's result. 176 177 178 (define (new-niftier-rng) 179 (let* {[super (new-rng)] ; The superclass object. 180 [name "hello"]} ; A new field, only in the subclass. 181 (lambda (msg . other-args) 182 (cond [(symbol=? msg 'skip) (begin (super 'next) "skipped")] 183 [(symbol=? msg 'next) (* 2 (super 'next))] 184 #;[(symbol=? msg 'get-seed) sseed] 185 ; This is what we *want* to return, but it'd be an error: sseed 186 ; is in super's scope, but not ours! 187 ; Our approach to implementing an object system can do most things, 188 ; but it can't emulate Java's 'protected' access 189 ; (since 'subclassing' this way is something any function can do). 190 [else (apply super msg other-args)])))) 191 192 193 ;;; Exercise: our methodology for faking objects (by using closures and 194 ;;; a 'dispatcher' function) does allow for calling superclass methods 195 ;;; (through a variable we conveniently named `super`). 196 ;;; However, how could we call methods in the *same* class? 197 ;;; Hint: include the dispatcher method inside the let*, 198 ;;; perhaps naming it `this`. 199 ;;; But `let*` won't quite work; you'll need `letrec`. 200 201 202 203 204 "v5 (subclassing)" 205 (define ss (new-niftier-rng)) 206 (ss 'next) 207 (ss 'next) 208 (ss 'skip) 209 (ss 'next) 210 (ss 'seed! 1) 211 (ss 'next) 212 213 214 215 #| "Let over lambda": 216 The sandwiching of 'lambda' and 'let' is doing interesting things for us. 217 (And fwiw, recall that let can be re-written in terms of lambda...so 218 lambda alone is enough to implement objects!) 219 220 Hey, our own language N4 has both 'let' and 'lambda' -- 221 that means we can essentially implement subclassing and polymorphism! 222 |# |
home—lectures—exams—hws—breeze (snow day)
©2012, Ian Barland, Radford University Last modified 2012.Nov.26 (Mon) |
Please mail any suggestions (incl. typos, broken links) to ibarland ![]() |
![]() |