Midterm Exam Spring '23 v1 (Solutions)

.pdf

School

University of California, Los Angeles *

*We aren’t endorsed by this school

Course

131

Subject

Computer Science

Date

Dec 6, 2023

Type

pdf

Pages

5

Uploaded by ColonelRockGoldfinch39

CS131 Spring 23 - Midterm #1 version 1 rubric 1. [10 points-2 each] For each of the items below, write a Haskell type signature for the expression. If the item is a function then use the standard haskell type notation for a function. If the item is an expression, write the type of the expression (e.g., [Int]). For any answers that use one or more type variables where concrete types can't be inferred , use "t1", "t2", etc. for your type variable names. a. foo bar = map (\x -> 2 * x) bar b. z = \x -> x ++ ["carey"] c. m = [((\a -> length a < 7) x,take 3 y) | x <- ["matt","ashwin","siddarth","ruining"], y <- ["monday","tuesday","wednesday","thursday","friday"]] d. z = foldl (\x y -> x ++ y) e. foo bar = [] Answers: Any option listed below is worth full credit. Answers that fail to use types t1, t2, etc. but instead use other letters or type names should get full credit if their answer is valid. An answer is either entirely correct or entirely wrong. a. foo :: Num t1 => [t1] -> [t1] foo :: [Int] -> [Int] foo :: [Integer] -> [Integer] full points if they don’t include the function name (e.g. ‘foo ::’) full points if they don’t use a generic for instance of the Num class (e.g. giving full points for ‘Num => [Num] -> [Num]’ b. z :: [[Char]] -> [[Char]] z :: [String] -> [String] c. m :: [(Bool, [Char])] m :: [(Bool, String)] [(Bool, [Char])] [(Bool, String)] d. z :: [t1] -> [[t1]] -> [t1] z :: Foldable t2 => [t1] -> t2 [t1] -> [t1] note: the second answer involves type classes, which is out of scope of the class! e. foo :: t1 -> [t2] 2. [5 points] Suppose a language does not support closures. Is it possible for the language to still support currying and partial function application? If so, how would this work; if not, explain why not. Note: Limit your answer to five or fewer sentences, and avoid adding superfluous, incorrect answers as this will result in a point deduction. Answer: Any answer that hits the following points gets full credit: Currying requires closures to capture free variables used in the inner lambda expressions. If there are no closures then we can't create curried functions or do partial application. If the student just says currying/PA is not possible but does not give a rationale they get 1 point If the student also includes superfluous answers that are not correct, take one point off for each incorrect answer that is present. The minimum score for this problem is zero.
3. [16 points-2/2/2/10] In this question, you will be implementing directed graph algebraic data types and algorithms in Haskell. Recall that a graph is composed of nodes that hold values, and edges which connect nodes to other nodes. In a directed graph, edges are unidirectional, so an outgoing edge from node A to node B does NOT imply that B also has a direct connection to A. You may assume that all graphs have at least one node. a. Show the Haskell definition for an algebraic data type called "Graph" that has a single “Node” variant. Each Node must have one Integer value, and a list of zero or more adjacent nodes that can be reached from the current node. Answer: Any of the following answers is OK: data Graph = Node Int [Graph] data Graph = Node Integer [Graph] data Graph = Node [Graph] Int data Graph = Node [Graph] Integer If the student uses a type variable with a type of Integral that's ok too. All other answers get a zero. b. Using your Graph ADT, write down a Haskell expression that represents a graph with two nodes: 1. A node with the value 5 with no outgoing edges 2. A node with the value 42, with an outgoing edge to the previous node Answer: The students may use any variable names they like (instead of a and b). Given these definitions from part a: data Graph = Node Int [Graph] data Graph = Node Integer [Graph] Either of the following options are valid: a = Node 5 [] – 1 point b = Node 42 [a] – 1 point b = Node 42 [Node 5 []] – 2 points Given these definitions from part a: data Graph = Node [Graph] Int data Graph = Node [Graph] Integer Either of the following options are valid: a = Node [] 5 – 1 point b = Node [a] 42 – 1 point b = Node [Node [] 5] 42 – 2 points c. Carey has designed his own graph ADT, and written a Haskell function that adds a node to the “front” of an existing graph g that is passed in as a parameter: add_to_front g = Node 0 [g] In Haskell, creating new data structures incurs cost. Assuming there are N nodes in the existing graph g , what is the time complexity of Carey's function (i.e., the big-O)? Why? Answer: O(1) because only a single new node is being created, and it links to the original graph. The existing graph need not be regenerated in any way. d. Write a function called sum_of_graph that takes in one argument (a Graph) and returns the sum of all nodes in the graph. Your function must include a type annotation for full credit. You may assume that the passed-in graph is guaranteed to have no cycles. You may have helper function(s). Your solution MUST be shorter than 8 lines long. Answer: Any of these answers deserves full marks. They require one of the following type annotations: sum_of_graph :: Graph -> Int sum_of_graph :: Graph -> Integer --- carey's solution sum_of_graph (Node val edges) = val + (sumx_aux edges) where value (Node val edges) = val + (sumx_aux edges) sumx_aux edges = sum [value n | n <- edges] --- matt’s solution (map + sum) sum_of_graph (Node val edges) = val + sum (map sum_of_graph edges) --- matt’s solution (map + fold) sum_of_graph (Node val edges) = foldl (+) val (map sum_of_graph edges) --- optionally, students might include a base case like the following, though observe that it’s not strictly necessary sum_of_graph (Node val []) = val --- many other solutions are possible. other neat ones we saw included: --- - parsing the edges node-by-node, which required: --- - a mutually recursive helper function --- - or, “recreating” a new node with value 0, and the tail as its edges --- - foldl/foldr, but calling sum_of_graph on each edge Rubric Sketch (negative grading) Perfect (-0 pts) Minor syntax error(s) that did not affect understanding (-1 pts) ex: forgetting the parens for an ADT variant argument Incorrect base case / singleton node (-2 pts) ex: base case has value 0 Minor recursive logic bug (-2 pts) requires a fully-working solution, with one minor tweak ex: switching the order of the args to foldl/foldr ex: used sum improperly Major recursive logic bug / multiple minor bugs (-5 pts) ex: recursive solution tries to add a Graph and Integer ex: recursive solution tries to call sum_of_graph [Graph] ex: recursive solution misses multiple levels of children Incorrect/missing type definition (-1 pts) all-or-nothing; did give ECF if only submitted typedef, received 1 pt total Did not attempt (-10 pts) A handful of students noted that our definition of acyclic was unclear (is this acyclic in the undirected sense, or in the directed sense)? The latter has a “diamond problem” built-in; we were expecting solutions for the former. If you tried to deal with this but had a minor logic bug, we gave you full credit.
4. [10 points] Write a Haskell function called get_every_nth that takes in an Integer n and a list of generic types that returns a sublist of every n th element. For example: get_every_nth 2 ["hi","what's up","hello"] should return ["what's up"] get_every_nth 5 [31 .. 48] should return [35, 40, 45] Your function must have a type signature and must use either filter, foldr or foldl. It must be less than 8 lines long. Hint: If you use fold, your accumulator doesn't need to be the same type as your returned value or your input, and a tuple might be useful! Carey's answer: get_every_nth :: Integer -> [a] -> [a] get_every_nth n lst = map (\tup -> snd tup) -- or map (\(_,x) -> x) (filter (\tup -> (fst tup) `mod` n == 0) (zip [1..] lst)) Ruining's answer: get_every_nth :: Integer -> [a] -> [a] get_every_nth n lst = let f = \(res,index) x -> if mod index n == 0 then (x:res, index+1) else (res,index+1) -- this 'let' is one line in reverse( fst (foldl f ([],1) lst)) also acceptable; (\(x,_) ->x) instead of fst Possible common mistakes: - 0/10 for empty/ all wrong - 2/10 for an ok attempt (correct type, usage of functions is alright) - 5/10 for good idea - 7/10 for multiple syntax/edge problems - indexing off - 9/10 for syntax/edge problems (might bump up, not sure) - wrong operator/symbol - reverse - convert tuple to list - 10/10 for perfect (comprehensions count as filters) 5. [5 points] Write a Haskell comprehension that generates an infinite list of functions, each of which takes a single argument x, such that the k th function returns x k . You may assume that k starts at 1 for the first generated function, 2 for the second function, etc. For example: inf_list = [your comprehension here] head inf_list 9 → returns 9 head (tail inf_list) 9 → returns 81 Answer: inf_list = [\x -> z^x | z <- [1..]] – carey's answer Possible common mistakes: - not returning a list of functions ([z^x | z <- [1..]]) -> -3 pts - using the wrong operator (neither ** or ^) -> -3 pts - extraneous argument in lambda ([\x k -> x^k | k <- [1..]] -> -1 pt 6. [10 points-5/5] Consider the following Python program: class Comedian: def __init__(self, joke): self.__joke = joke def change_joke(self, joke): self.__joke = joke def get_joke(self): return self.__joke def process(c): # line A c[1] = Comedian("joke3") c.append(Comedian("joke4")) c = c + [Comedian("joke5")] c[0].change_joke("joke6") def main(): c1 = Comedian("joke1") c2 = Comedian("joke2") com = [c1,c2] process(com) c1 = Comedian("joke7") for c in com: print(c.get_joke()) a. Assuming we run the main function, what will this program print out? Answer: Partial credit for this part (a) and the next part (b) is only awarded if either the student fails to properly take into account a single valid mutation, or incorporates a single invalid mutation when there wasn't supposed to be one. Rubric for MT1 6.a 5 points for: joke6 joke3 joke4 2.5 points for: joke6 joke2 joke4 2.5 points for: joke6 joke3 2.5 points for: joke6 joke3 joke4 joke5 2.5 points for: joke1 joke3 joke4 2.5 points for: joke7 joke3 joke4 All other answers get a zero
Your preview ends here
Eager to read complete document? Join bartleby learn and gain access to the full version
  • Access to all documents
  • Unlimited textbook solutions
  • 24/7 expert homework help