Sample Final 4Date: Monday, April 26th |
AdministrativeThis exam was given in the Fall 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 |
As we have discussed in class, we can get the benefits of functional (side-effect-free) programming in an eager side-effect-full language by using thunks (nullary functions) to wrap side-effects, turning them into plain values. Using this, you get a simple functional world with no side-effects to complicate things, while still being able to conveniently interact with the “real world”.
For example, say that we have a set of Logo-like drawing primitives, including:
(: pen-down : -> Void)
;; lowers the pen down to the paper
(: pen-up : -> Void)
;; raises the pen from the paper
(: move : Number -> Void)
;; moves the pen N pixels in its current direction, drawing if
;; it is currently on the paper
(: turn : Number -> Void)
;; turn the direction the pen will move by N degrees |
(: PenDown : -> (-> Void))
(define (PenDown) pen-down)
(: PenUp : -> (-> Void))
(define (PenUp) pen-up)
(: Move : Number -> (-> Void))
(define (Move n) (lambda () (move n)))
(: Turn : Number -> (-> Void))
(define (Turn n) (lambda () (turn n))) |
Now, to use these values, we need some convenient utilities. Some of these utilities can be specific to the Logo world, for example:
(: WithPenDown : (-> Void) -> (-> Void))
;; turns an operation into one that is performed with the pen
;; temporarily down (assuming that the pen usually stays up).
(define (WithPenDown op)
(lambda ()
(pen-down)
(op)
(pen-up))) |
(define (WithPenDown op)
(Combine (Combine (PenDown) op) (PenUp))) |
(: Square : Number -> (-> Void))
;; make a square of the given size
(define (Square n)
(Repeat 4 (Combine (WithPenDown (Move n)) (Turn 90)))) |
Question 2: Language Extension: Extending Scheme | 18 pts |
In several occasions, we have seen how curried functions can be a very useful tool. To make it convenient to write curried functions, we want to extend Scheme with a new form: clambda, that creates a curried lambad. To demonstrate how it is used:
(clambda (a b c d) (+ (* a b) (* c d)))
; should expand to
(lambda (a)
(lambda (b)
(lambda (c)
(lambda (d)
(+ (* a b) (* c d)))))) |
Implement this clambda form as a macro, using define-syntax and syntax-rules. You don’t need to make it work on no arguments — there is no point in currying that case. Note that the solution is relatively short (about 4-6 lines should be sufficient).
Question 3: Language Extension: Extending Toy | 32 pts |
In Assignment #10 we have implemented an extension to the TOY language that has by-reference rfun functions. An alternative approach is what you get in C: extend the language with a new kind of “reference” values, which hold the box that is the location of some value. This extension should be a familiar process: we’re taking some feature of our language that is currently second-class, and we promote it to a first class value that is accessible from inside the language. In the C case, this means exposing raw machine pointers; and in our case, we take the boxes that are used to store binding values and expose them. These boxes are currently available only in the extended TOY implementation — in Scheme code, and we will make them accessible inside the language, so they can be passed around and used as any other kind of values in TOY programs.
To get a quick idea of how this extension will look like, here is a test that will eventually work:
(test (run "{bind {{x 1}
{incref! {fun {x} {setref! x {+ x 1}}}}}
{bind {{*x {ref x}}}
{incref! *x}
{incref! *x}
*x}}")
=> 3) |
As usual, we begin by extending the BNF,
<TOY> ::= <num>
| <id>
| { ref <id> } ; <-- new special form
| { set! <id> <TOY> }
| ...same... |
(define-type TOY
[Num (n Number)]
[Id (name Symbol)]
[Ref (name Symbol)] ; <-- new variant
[Set (name Symbol) (new TOY)]
...same...) |
(define-type VAL
[BogusV]
[ScmV (x Any)]
[RefV (b (Boxof VAL))] ; <-- new value type
[FunV (names (Listof Symbol))
(body (Listof TOY))
(env ENV)
(byref? Boolean)]
[PrimV (prim ((Listof VAL) -> VAL))]) |
[(Ref name) (RefV —«fill-in»—)] |
{setref! foo bar} |
(define global-environment
(FrameEnv (list (list '+ (scheme-func->prim-val +))
...same...
(list 'setref! (box (PrimV setref-function)))
;; values
...same...)
(EmptyEnv))) |
(: setref-function : (Listof VAL) -> VAL)
;; the implementation of the builtin "set-ref!" function that changes
;; the contents of a ref value
(define (setref-function args)
(if (= (length args) 2)
(cases (car args)
[(RefV b) —«fill-in»—]
[else (error 'setref! "got a non-ref value: ~s" (car args))])
(error 'setref! "bad number of arguments, expecting two"))) |
{setref! x {+ x 1}} |
(: deref-value : VAL -> VAL)
;; utility function that automatically converts a ref value to a plain
;; value
(define (deref-value val)
—«fill-in»—) |
(map (lambda: ([a : VAL])
(cases a
[(ScmV v) v]
[else (error ...)]))
args) |
(map (lambda: ([a : VAL])
(cases (deref-value a)
[(ScmV v) v]
[else (error ...)]))
args) |
Question 4: Lazy Languages | 18 pts |
Question 3 was somewhat similar to the Sloth implementation in that a certain value is automatically converted to another one. But there is one thing that we did in the Sloth implementation, but didn’t do here: in Sloth, note that there is a second boolean argument to scheme-func->prim-val, which determines if values are forced or not, and was used in a particular way by the global list binding (of the Sloth language).
You need to figure out what is it exactly that is missing, and how it would affect the code if it is added as in the Sloth implementation. That is, understand what the extra boolean flag causes if our evaluator is also extended with it. You will need to assume that the language is also extended with list or cons.
Once you know what will change, demonstrate this: you need to write a sample program for our extended TOY evaluator, such that it will return a different result if the boolean flag is added (and the code in scheme-func->prim-val is changed to use it as Sloth does) or if not.
(Note: it’s TOY sample code that is needed here.)
Question 5: Language Features | 20 pts |
In the following sub-questions, you should choose the valid answer. Only one should be chosen, unless the question explicitly says otherwise.
Question 6: Type System | 20 pts |
Finally, to continue with the spirit of mutation, we will extend the statically-typed Picky language with mutation. Start with the basic Picky language definition, given here so you don’t need to wonder which version you need:
<PICKY> ::= <num>
| <id>
| { fun { <id> : <TYPE> } : <TYPE> <PICKY> }
| { + <PICKY> <PICKY> }
| { call <PICKY> <PICKY> }
<TYPE> ::= Number
| ( <TYPE> -> <TYPE> )
Γ ⊢ n : Number
Γ ⊢ x : Γ(x)
Γ ⊢ a : Number Γ ⊢ b : Number
|
You need to add the following to the BNF:
Once you have that, write two new typing judgements — one for set!, which should evaluate to a Void value, and one for begin, which should evaluate to the result of its second (and last) subexpression. Be careful with set! — it should not be possible to change the type of an identifier, since this will break the invariants that the type checker enforces.