|
| 1 | +#lang scribble/manual |
| 2 | + |
| 3 | +@(require (for-label racket) |
| 4 | + "../notes/ev.rkt") |
| 5 | + |
| 6 | +@title{Midterm 2} |
| 7 | + |
| 8 | +@bold{Due: Thurs, Oct 14, 11:59PM} |
| 9 | + |
| 10 | +@(define repo "https://classroom.github.com/a/bJm4_Ug6") |
| 11 | + |
| 12 | +Midterm repository: |
| 13 | +@centered{@link[repo repo]} |
| 14 | + |
| 15 | +The repository contains a single markdown file @tt{m2.md}, which you |
| 16 | +can edit to submit your answers to the following questions. Your |
| 17 | +submision must be pushed by midnight on Thursday. |
| 18 | + |
| 19 | +During the 48 hours of the exam period, you may only ask private |
| 20 | +questions on Piazza if you need assistance for the course staff. You |
| 21 | +may not comminicate or collaborate with any one else about the content |
| 22 | +of this exam. |
| 23 | + |
| 24 | +@section[#:tag-prefix "m2"]{Short answer} |
| 25 | + |
| 26 | +@bold{Question 1} |
| 27 | + |
| 28 | +[12 points] |
| 29 | + |
| 30 | +Using only @racket[cons], @racket['()], symbols, and literal numbers, |
| 31 | +strings, booleans, or characters, write expressions that are |
| 32 | +equivalent to each of the following: |
| 33 | + |
| 34 | +@itemlist[ |
| 35 | + |
| 36 | +@item{@verbatim{'((1) x 2)}} |
| 37 | + |
| 38 | +@item{@verbatim{'((1) x . 2)}} |
| 39 | + |
| 40 | +@item{@verbatim{'(1 . (2 . (3)))}} |
| 41 | + |
| 42 | +@item{@verbatim{'(quote (x 2))}} |
| 43 | + |
| 44 | +@item{@verbatim{`(1 ,(add1 2))}} |
| 45 | + |
| 46 | +@item{@verbatim|{`(1 ,@'(2 3) x)}|} |
| 47 | +] |
| 48 | + |
| 49 | +For example, @racket['(1 2 3)] is equivalent to @racket[(cons 1 (cons 2 (cons 3 '())))]. |
| 50 | + |
| 51 | +@bold{Question 2} |
| 52 | + |
| 53 | +[10 points] |
| 54 | + |
| 55 | +Will the following program run forever using only a constant amount of |
| 56 | +memory, or will it eventually consume all memory and crash? Briefly |
| 57 | +justify your answer. |
| 58 | + |
| 59 | +@#reader scribble/comment-reader |
| 60 | +(racketblock |
| 61 | +(begin (define (flip x) |
| 62 | + (flop (add1 x))) |
| 63 | + (define (flop y) |
| 64 | + (flip (sub1 x))) |
| 65 | + (flip 5)) |
| 66 | +) |
| 67 | + |
| 68 | +How about this one? Again, justify your answer. |
| 69 | + |
| 70 | +@#reader scribble/comment-reader |
| 71 | +(racketblock |
| 72 | +(begin (define (flip x) |
| 73 | + (flip (flop (add1 x)))) |
| 74 | + (define (flop y) |
| 75 | + (flop (flip (sub1 x)))) |
| 76 | + (flip 5)) |
| 77 | +) |
| 78 | + |
| 79 | + |
| 80 | +@bold{Question 3} |
| 81 | + |
| 82 | +[8 points] |
| 83 | + |
| 84 | +Which of the following subexpressions are in tail position? |
| 85 | + |
| 86 | +@itemlist[ |
| 87 | + |
| 88 | +@item{@verbatim{(if e0 e1 e2)}} |
| 89 | + |
| 90 | +@item{@verbatim{(match e0 [p1 e1] [p2 e2])}} |
| 91 | + |
| 92 | +@item{@verbatim{((λ (x y) e0) e1 e2)}} |
| 93 | + |
| 94 | +@item{@verbatim{(eq? e0 e1)}} |
| 95 | + |
| 96 | +] |
| 97 | + |
| 98 | + |
| 99 | + |
| 100 | + |
| 101 | + |
| 102 | + |
| 103 | +@section[#:tag-prefix "m2"]{Code generation} |
| 104 | + |
| 105 | +@bold{Question 4} |
| 106 | + |
| 107 | +[20 points] |
| 108 | + |
| 109 | +Suppose we wanted to add a @racket[set-box!] operation to our language. |
| 110 | + |
| 111 | +A @racket[(set-box! _e0 _e1)] expression evaluates @racket[_e0] and |
| 112 | +@racket[_e1]. The result of @racket[_e0] should be a box (otherwise |
| 113 | +an error is signalled). The box is updated (mutated) to contain the |
| 114 | +value of @racket[_e1]. Racket's @racket[set-box!] returns a special |
| 115 | +value called @racket[void], but your compiler may have the expression |
| 116 | +return any value. |
| 117 | + |
| 118 | +Here's an example (note: @racket[let] is used for sequencing here): |
| 119 | + |
| 120 | +@ex[ |
| 121 | +(let ((b (box 10))) |
| 122 | + (let ((i1 (set-box! b 2))) |
| 123 | + (unbox b))) |
| 124 | +] |
| 125 | + |
| 126 | +Implement the following function in the compiler. (You may assume |
| 127 | +this code will be added to the Loot compiler and may use any functions |
| 128 | +given to you.) |
| 129 | + |
| 130 | +@#reader scribble/comment-reader |
| 131 | +(racketblock |
| 132 | +;; LExpr LExpr CEnv -> Asm |
| 133 | +;; Compiler for (set-box! e0 e1) |
| 134 | +(define (compile-set-box! e0 e1 c) ...) |
| 135 | +) |
| 136 | + |
| 137 | +@section[#:tag-prefix "m2"]{Defunctionalizing} |
| 138 | + |
| 139 | +@bold{Question 5} |
| 140 | + |
| 141 | +[20 points] |
| 142 | + |
| 143 | +Here is a program we wrote for computing the product of a binary tree |
| 144 | +of numbers. |
| 145 | + |
| 146 | +It is clever in that it never multiplies if there is a zero in the tree; |
| 147 | +it immediately returns @racket[0]. It does this without using |
| 148 | +exception handlers, but instead by being written in a |
| 149 | +continuation-passing style. |
| 150 | + |
| 151 | +@#reader scribble/comment-reader |
| 152 | +(racketblock |
| 153 | +;; BT -> Number |
| 154 | +(define (prod bt) |
| 155 | + (prod/k bt (λ (x) x))) |
| 156 | + |
| 157 | +;; BT (Number -> Number) -> Number |
| 158 | +(define (prod/k bt k) |
| 159 | + (match bt |
| 160 | + ['leaf (k 1)] |
| 161 | + [`(node ,v ,l ,r) |
| 162 | + (if (zero? v) |
| 163 | + 0 |
| 164 | + (prod/k l (λ (pl) |
| 165 | + (prod/k r (λ (pr) |
| 166 | + (k (* v (* pl pr))))))))])) |
| 167 | +) |
| 168 | + |
| 169 | +Use defunctionalization to derive an equivalent definition of |
| 170 | +@racket[prod] that does not use @racket[λ]-expressions or higher-order |
| 171 | +values (i.e. no functions consume or produce other others). |
| 172 | + |
| 173 | +The resulting program should consist of three mutually-recursive, |
| 174 | +first-order functions where every call to one of these functions is a |
| 175 | +tail-call. |
| 176 | + |
| 177 | +For full credit, be sure to include a type definition for the type of |
| 178 | +defunctionalized @racket[λ]-expressions in this program and type |
| 179 | +signatures for all three functions. |
| 180 | + |
| 181 | + |
| 182 | + |
| 183 | +@section[#:tag-prefix "m2"]{Pattern matching} |
| 184 | + |
| 185 | +@bold{Question 6} |
| 186 | + |
| 187 | +[30 points] |
| 188 | + |
| 189 | +When we studied how to transform away pattern-matching expressions, |
| 190 | +we considered the following grammar of patterns: |
| 191 | + |
| 192 | +@#reader scribble/comment-reader |
| 193 | +(racketblock |
| 194 | +;; type Pat = |
| 195 | +;; | #t |
| 196 | +;; | #f |
| 197 | +;; | Integer |
| 198 | +;; | String |
| 199 | +;; | Variable |
| 200 | +;; | `_ |
| 201 | +;; | `'() |
| 202 | +;; | `(quote ,Symbol) |
| 203 | +;; | `(cons ,Pat ,Pat) |
| 204 | +;; | `(list ,Pat ...) |
| 205 | +;; | `(? ,Expr ,Pat ...) |
| 206 | + ) |
| 207 | + |
| 208 | +Let's make a modest extension: |
| 209 | +@#reader scribble/comment-reader |
| 210 | +(racketblock |
| 211 | +;; type Pat = |
| 212 | +;; ... |
| 213 | +;; | (list 'list Pat '...) |
| 214 | + ) |
| 215 | + |
| 216 | +The pattern @racket[(list _p ...)] is a pattern that matches a list of |
| 217 | +any length, so long as every element of the list matches the |
| 218 | +subpattern @racket[_p]. Note that the elipsis here is literally part |
| 219 | +of the syntax! |
| 220 | + |
| 221 | +If the pattern matches, it matches any pattern variables within |
| 222 | +@racket[_p] to the @emph{list} of things that match in the elements of |
| 223 | +the list. |
| 224 | + |
| 225 | +Some examples: |
| 226 | + |
| 227 | +@ex[ |
| 228 | +(match (list 1 2 3) |
| 229 | + [(list xs ...) (reverse xs)]) |
| 230 | + |
| 231 | +(match (list 'x 'y 'z) |
| 232 | + [(list (? symbol? xs) ...) xs]) |
| 233 | + |
| 234 | +(match (list) |
| 235 | + [(list (? symbol? xs) ...) xs]) |
| 236 | + |
| 237 | +(match (list 'x 3 'z) |
| 238 | + [(list (? symbol? xs) ...) xs] |
| 239 | + [_ '()]) |
| 240 | + |
| 241 | +(match '((x 1) (y 2) (z 3)) |
| 242 | + [(list (list xs ys) ...) (list xs ys)]) |
| 243 | +] |
| 244 | + |
| 245 | + |
| 246 | +Extend the definitions of @racket[pat-match] and @racket[pat-bind] |
| 247 | +which wrote when implementing pattern matching to include this new |
| 248 | +kind of pattern. |
| 249 | + |
| 250 | +@#reader scribble/comment-reader |
| 251 | +(racketblock |
| 252 | +;; Pat Variable -> Expr |
| 253 | +;; Produces an expression determining if p matches v |
| 254 | +(define (pat-match p v) |
| 255 | + (match p |
| 256 | + [(list 'list p1 '...) |
| 257 | + ;; your solution here |
| 258 | + 'todo] |
| 259 | + ;; omitted code that was previously given |
| 260 | + )) |
| 261 | + |
| 262 | +;; Pat Variable Expr -> Expr |
| 263 | +;; Produce an expression that deconstructs v and binds pattern variables |
| 264 | +;; of p in scope of e. |
| 265 | +;; ASSUME: v matches p |
| 266 | +(define (pat-bind p v e) |
| 267 | + (match p |
| 268 | + [(list 'list p1 '...) |
| 269 | + ;; your solution here |
| 270 | + 'todo] |
| 271 | + ;; omitted code that was previously given |
| 272 | + )) |
| 273 | +) |
| 274 | + |
| 275 | +You do not have to transcribe the complete function, just give the |
| 276 | +code that goes in two occurrences of @racket['todo] to complete the |
| 277 | +definition. |
| 278 | + |
| 279 | +If you need to rely on any helper functions, you must give their |
| 280 | +complete definition and type signatures. |
| 281 | + |
0 commit comments