RU beehive logo ITEC dept promo banner
ITEC 380
2013fall
ibarland
aaray

homelecturesrecipeexamshwsD2Lbreeze (snow day)

lect40b-scope-objects
let over lambda

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

homelecturesrecipeexamshwsD2Lbreeze (snow day)


©2013, Ian Barland, Radford University
Last modified 2013.Dec.02 (Mon)
Please mail any suggestions
(incl. typos, broken links)
to ibarlandradford.edu
Powered by PLT Scheme