Sample Final 3Date: Monday, April 26th |
AdministrativeThis exam was given in the Spring semester of 2009. |
| |||||||||||||||||||||||||
Remember: the correct answers are short. Also, questions that ask for a verbal answer rather than code should still be answered correctly and based on facts.
Question 1: Scheme Programming | 20 pts |
A memoized function is a function that “remembers” its answers. That is, you construct a function as usual, except that each time it is applied, it will consult a local cache for the function. If there is no cached answer for the input value, then we compute it, store the result in the cache, and return it. Next time the function is called with the same value, it will just retrieve the result from the cache.
In this question, you will implement a memoization function — a higher order function that consumes a unary (numeric) function and produces a memoized version of it. It is common to use a hash table for the cache, but in this question you will implement it with an association list, stored in a box so you can add new cached results to it.
For the cache we will use these values:
null ; an empty cache
(cons (list 1 2) cache) ; extending cache by mapping 1 to 2
assoc ; looking up a value (will be implemented as lookup
below) |
(box null) ; an empty cache
(set-box! the-cache ...) ; change the cache |
(: lookup : Number (Boxof (Listof (List Number Number)))
-> (U #f Number))
;; looks up the value in the cache; returns the mapped number, or
;; #f if not found
(define (lookup val cache)
(define (helper alist)
(cond [(null? alist) #f]
[(= val (first (first alist))) (second (first alist))]
[else (helper (rest alist))]))
(helper (unbox cache))) |
(: fib : Number -> Number)
(define (fib n) (if (<= n 1) 1 (+ (fib (- n 1)) (fib (- n 2))))) |
(define mfib (memoize fib)) |
> (mfib 40)
165580141 ; after a long time
> (mfib 40)
165580141 ; immediately
> (mfib 39)
102334155 ; after a long time still |
Question 2: Language Extension: Extending Scheme | 20 pts |
(: fib : Number -> Number)
(define-memoized (fib n)
(if (<= n 1) 1 (+ (fib (- n 1)) (fib (- n 2))))) |
> (fib 40)
165580141
> (fib 40)
165580141
> (fib 39)
102334155 |
Question 3: Language Features | 21 pts |
Question 4: Language Extension: Extending Toy | 20 pts |
We want to extend the Toy evaluator with a let/cc, as in Scheme. The first part of this is straightforward:
<TOY> ::= <num>
| ...
| { let/cc <id> <TOY> }
| ... |
(define-type TOY
...
[LetCC (name Symbol) (body TOY)]
...) |
...
[(cons 'let/cc more)
(match sexpr
[(list 'let/cc (symbol: name) body)
(LetCC name (parse-sexpr body))]
[else (error 'parse-sexpr
"bad `let/cc' syntax in ~s" sexpr)])]
... |
The second part is in the evaluator — where the real work is done. There are two common ways to implement continuations: either convert the input program to be in continuation passing style, or use the underlying system to provide them for us. The first way will involve substantially changing the evaluator, so we go with the second: expose the continuation facility in our underlying system. Specifically, we will use Scheme’s let/cc to implement our own let/cc. So, assuming that we have let/cc in our Scheme (with the right type), you need to write the evaluation case for the new Toy let/cc:
[(LetCC name bound-body)
... your code here ...] |
What all of this is doing is capturing the actual evaluator’s continuation, and wrapping it in a user-accessible PrimV — so we’re effectively embedding a PLT Scheme feature into our own language. As with other cases of feature embedding that we’ve seen, the result will not be an explanation of how continuations are implemented — and more specifically, you need to know very little about continuations to answer this question.
Question 5: Programming in a Lazy Language | 21 pts |
(letrec ([weird (list weird weird)])
(length weird)) |
(letrec ([x (+ z 1)]
[y 3]
[z (* y 2)])
x) |
(letrec ([x (+ z 1)]
[y (/ x 2)]
[z (* y 2)])
x) |
Question 6: Type System | 20 pts |
We start with the simple Picky language that we’ve been using in class to demonstrate static typing, and extend it with pairs. This means that we extend the syntax with cons, car, and cdr, and we also add a new Pair(A,B) type constructor:
<PICKY> ::= <num>
| <id>
| { fun { <id> : <TYPE> } : <TYPE> <PICKY> }
| { + <PICKY> <PICKY> }
| { cons <PICKY> <PICKY> } ; <<<\
| { car <PICKY> } ; <<< > new expressions
| { cdr <PICKY> } ; <<</
| { call <PICKY> <PICKY> }
<TYPE> ::= Number
| ( <TYPE> -> <TYPE> )
| Pair(<TYPE>,<TYPE>) ; <<<-- new type |
Your job is to finish this work: write the three type judgement rules for the new operators — all three will use the new type constructor in some way.