This is a closed book, no-computer, no calculator, no smart-phone, no cow, do it all by
yourself exam.
There are seven questions, most with sub-questions. Make sure to answer all of them.
Write your answers in the provided books (or if you’re taking the exam with a proctor, use
whatever paper you brought with you.) Make sure to write your name on each book that
you use to record your answers. Make sure to write legibly. Good luck!
-
[3 points each, 21 points total] Using a sentence or two, explain each of the followingterms in the context of this class.
- higher-order function
Answer: A Higher Order Function is a function that takes a function as a parameter and produces another function
- mutex lock
Answer: Mutex Lock - Mutual Exclusion Lock, so that threads do not access the same resource at the same time.
- sub-classing (also known as inheritance)
Answer: Inheritance is so to speak a way to 'inherit' methods from another class so as to reuse code.
- parametric polymorphism
Answer: A function that allows any type as a paremeter (e.g. 'a in ocaml)
- busy waiting
Answer: Occurs when a thread repeatedly checks if an action occured (e.g polling) which can be bad since it uses resources.
- overriding
Answer: Overriding refers to the 'redefining' the method implementation of an inherited class, therefore overriding the parent's definition.
- event listener
Answer: A Listener for Events! A function that is called whenever an event fires.
- higher-order function
- . [2 points each, 16 points total] Answer True or False for each of the following questions.
- If a computation runs in O(2n+3n2+10) time, then it also runs in O(n) time.
Answer: false
-
We can implement an imperative queue where the enqueueand dequeueoperations take worst case time O(1).Answer: true
-
The parallel merge-sort algorithm shown in class takes time O(lg n) if we have nprocessors.Answer: false
- A deadlock occurs when two or more threads try to acquire the same lock.
Answer: true
-
Suppose class D does not inherit from class C. Suppose further that objectsgenerated from class C have type T. Then objects generated from D cannot havea sub-type of T.Answer: false
- It's impossible to get a race condition when we use purely functional code.
Answer: true
-
Suppose f is a purely functionalOCaml function with type unit->int. Thenf returns the same integer each time we call it.Answer: true
-
Determining whether two balanced, binary trees of n bignums are equal can bedone in O(n) time.Answer: false
-
[0 points] The answer to this question is "false".Answer: Paradox!?
- If a computation runs in O(2n+3n2+10) time, then it also runs in O(n) time.
-
[4 points each, 24 points total] For each of the following OCaml expressions, give codethat when substituted for the ‘???’ causes the whole expression to evaluate to 42, orelse argue that the program cannot be made to evaluate to 42. Your code should avoidshadowing any of the defined variables (e.g., your code should not include a “let”.)
let x = ref 0 in
let f () = !x in
let x = ref x in
??? ; f()Answer:(!x) := 42
let x = ref 0 in
let f () = !x in
let x = ref 42 in
??? ; f()Answer: Cannot be made to 42, x in line islet f x = x := (!x) + 1 in
let y = ref 0 in
List.map f ???Answer: []; 42type ilist = Nil | Cons of (int * ilist) ref
let f (x:ilist) =
match x with
| Nil -> 0
| Cons r -> (let (i,t) = !r in
match t with
| Nil -> 1
| Cons s -> if r == s then i else 2)
in
f (let f = ??? in ???)Answer: let f = Cons(ref(42, Nil)) in (match f with | Cons r -> r := (42, f) | Nil-> Invalid_argument "Impossible"); fclass c = object
method x = 41
end
class d = object
???
method x = bob#x + 1
end
(new d)#xAnswer: inherit c as bobclass c = object
val mutable x = ref 0
method get = !x
method set y = x <- y
end
let v = new c in ??? ; v#getAnswer: v#set (ref 42)
- [15 points total, 5 each] Consider the following module interfaces for numbers.
module type SIMPLE_NUMBER =
sig
type bignum
val from_int : int -> bignum
val minus : bignum -> bignum -> bignum
val less : bignum -> bignum -> bool
end
module type EXTENDED_NUMBER =
sig
include SIMPLE_NUMBER
val plus : bignum -> bignum -> bignum
val equal : bignum -> bignum -> bool
end
-
Write a functor that takes a SIMPLE_NUMBER module as an argument andreturns an EXTENDED_NUMBER module as a result. Keep your code as simple aspossible. We will even get you started:Answer: module Extend(S : SIMPLER_NUMBER) : EXTENDED_NUMBER =
struct
open S
(* your definitions go here... *)
let plus x y = minus x (minus y (from_int 0))
let equal x y = not (less x y) && not (less y x)
end -
In the Bignum problem set, we asked you to represent numbers with a verystrong representation invariant:there should be no leading zeros in the list ofdigits, and the "negative" flag should never be set for zero. Explain how thismade some operations easier to implement, and others harderAnswer: (* Wasn't the negative flag of type bool!? *)
The lack of leading zeroes made it easier to compare the bignums otherwise we would have to take the leading zeroes into account (which are for all intents and purposes nil). Made it harder for some operations which produced bignums though, since we have to make sure no leading zeros are produced. -
Suppose we asked you to build an implementation of Rational numbers(fractions) using a pair of Bignums (one for the numerator, one for thedenominator). What representation invariant(s) might you impose on your codeto make equality on Rationals easier?Answer: Always Lowest Terms
-
-
[13 pointstotal] We can describe an infinite, 2-dimensional plane of values using thefollowing recursive type definition:
open Lazy;;
type 'a plane = {
contents : 'a ;
north : 'a plane lazy_t ; south : 'a plane lazy_t ;
east : 'a plane lazy_t ; west : 'a plane lazy_t
};;
Each point contains some contents and links to the points north, south, east, and west.Recall that applying the built-in primitive lazy to an expression e of type t yields a tlazy_t, and delays the evaluation of e, whereas the primitive force takes a tlazy_t, and forces the expression to be evaluated to produce a t.-
[3 points] Write a map function which when given a function f from 'a to 'b,and an 'a plane, produces a 'b plane.Answer: let map (f:'a->'b) (a:'a plane) = {
contents = f a.contents,
north = lazy (map f (Lazy.force a.north)),
south = lazy (map f(Lazy.force a.south)),
east = lazy (map f(Lazy.force a.east)),
west = lazy (map f(Lazy.force a.west))
} -
[5 points] Write code to build the Cartesian plane. The Cartesian plane is an(int * int) planewhere the pair of integers represents the X and Ycoordinates respectively of a point in the plane. Your plane should start with theorigin (0,0), and as we move east, the X coordinate should increase, while aswe move west, the X coordinate should decrease. Similarly, moving north shouldcause the Y coordinate to increase, while moving south should cause the Ycoordinate to decrease.Answer: let cart = {
contents = (0, 0)
north = lazy (map (fun (x,y)-> (x, y+1)) cart),
south = lazy (map (fun (x,y)-> (x, y-1)) cart),
east = lazy (map (fun (x,y)-> (x+1, y)) cart),
west = lazy (map (fun (x,y)-> (x-1, y)) cart)
} -
[5 points] Suppose we are given a bool plane and we wish to determinewhether there is a true value in it somewhere. That is, we wish to write afunction that returns true if and only if the plane includes a true value anywherein the plane. Describe (in English or code) how you might do this, guaranteeingthat the function always terminates when there is a true value somewhere in theplane. (Warning: there is no guarantee that moving one direction (c.f., east) andthen the opposite direction (c.f., west) gets you back to the a node with the samecontents.)Answer: If going back to a step lead to the same node, it would be easy to do the same idea as if we were to fold the nodes. However, because we do not have this luxury, I guess what is possible is to use the same idea used on problem set 6, checking if a list is cyclic. What we could do is store nodes we have visited and their neighbors, and traverse them recursively and returning when we see true.
-
-
. [10 points] Recall our interface for events:
type id
type 'a event
val new_event : unit -> 'a event
val add_listener : 'a event -> ('a -> unit) -> id
val add_one_shot : 'a event -> ('a -> unit) -> id
val remove_listener : 'a event -> id -> unit
val fire_event : 'a event -> 'a -> unit
val run : (unit -> unit) -> unit
Suppose we are building a soda machine and the machine has a set of devices and
actuators with the following interface:
type soda = Coke | DietCoke | Sprite | MooJuice
val coin_inserted : int event
val cancel : unit event
val soda_requested : soda event
val return_money : int -> unit
val dispense_soda : soda -> unit
When the user inserts a coin into the machine, the coin_insertedevent is triggeredwith the value of the coin (e.g., 5 for a nickel, 10 for a dime, etc.) If the user wishes tocancel the transaction, then she presses the cancel button, triggering the cancelevent,at which point, any money she has deposited should be returned to her via thereturn_moneyoperation. When she presses a button for a soda, thesoda_requestedevent is triggered with the kind of soda she requested. If she hasdeposited at least $1, then the soda should be given to her via the dispense_sodaoperation, and any additional money should be returned to her via return_money.Write a set of Ocaml definitions so that when we call the event run function, we get theright behavior for the soda machine.Answer:
(*Writing Ocaml here, I realized how much I love emacs!*)
let money = ref 0 in
Event.add_listener coin_inserted (fun coins-> money := (!money+coins));
Event.add_listener cancel (fun () -> return_money (!money); money:=0);
Event.add_listener soda_requested (fun soda->
if !money > 100 then
(dispense_soda soda; return_money (!money - 100));
money :=0) - [1 point] What is the super secret bonus answer?
Answer: Cow!?