======================================================================================= === === === Sujet de l'examen === === === ======================================================================================= - Pour valider chaque fonction, vous devez obligatoirement effectuer le test automatique qui vous indiquera si votre fonction est correcte. Le test automatique est déjà présent dans le programme à compléter ('✔✔✔ Check your answer'). - Les fonctions n'ont pas besoin d'être tail-recursive, sauf lorsque c'est demandé explicitement. - Vous avez le droit d'utiliser les fonctions de la librairie standard (p. ex. List.filter), mais sans y être obligé. En particulier, vous pouvez utiliser List.rev pour construire une liste inverse si besoin. - Vous pouvez créer et utiliser autant de fonctions auxiliaires que vous souhaitez. - Les énoncés sont en anglais afin de rester familier avec le vocabulaire des leçons et exercices. - Le barème pour chaque question est indiqué de manière approximative avec des étoiles ★★. ======================================================================================= ----- Question 1 ★ ----- Write a function f1 : ∀ α β . (α → β) → (β → string) → (α → string) This is about exceptions. f1 expects two functions: g and tos (tos means to_string). It returns a new function g2 of type 'a -> string such that : - if g x returns a value y, then g2 x returns y as a string (y is converted to string using tos) - if g x raises an exception, then g2 x returns the string "exception". Examples let soi = string_of_int f1 (fun () -> 0) soi () ~~> "0" f1 (fun () -> raise Not_found) soi () ~~> "exception" ----- Question 2 ★★ ----- Write a function f2 : ∀ α . α → α → α list → α list f2 expects three arguments: x, y, and a list l. f2 must return the list l without the part which is between x and y. More precisely : - if x does not occur in the list l, return l. - if x occurs in l, return the list l without the part between the first x and the first y occurring strictly after x. - if x occurs in l, but no y is found strictly after x, returns the list from the beginning until the first x (without x). Examples let l = [ 1 ; 2 ; 3 ; 3 ; 4 ; 5 ; 6 ; 7 ] (* Notice: 3 occurs twice. *) f2 9 5 l ~~> l f2 5 5 l ~~> [ 1 ; 2 ; 3 ; 3 ; 4 ] f2 3 5 l ~~> [ 1 ; 2 ; 6 ; 7 ] f2 3 0 l ~~> [ 1 ; 2 ] f2 3 3 l ~~> [ 1 ; 2 ; 4 ; 5 ; 6 ; 7 ] f2 1 3 l ~~> [ 3 ; 4 ; 5 ; 6 ; 7 ] ----- Question 3 ★★ ----- Open types_tree.ml (with pluma) and read the type definitions (but do NOT copy it in your program). Write a function f3 : ∀ α . α tree → α f2 expects a tree (as defined in Types_tree). f2 must return the maximum value found in the tree (remember that comparisons are polymorphic). Examples Take a look at test tree number 4304: q3_qvalue 4304 ;; (* A tree with six nodes should be printed, with maximal value 3 (assuming I have the same tree than you). *) Then, you can directly test your function with q3_invok f3 4304 ;; Another test: (q3_qvalue 1702) has 8 nodes, max value is 4. ----- Question 4 ★ ----- Open types_filter.ml (with pluma) and read the type definitions (but do NOT copy it in your program). Write a value f4 : (int × int) filter f4 is a filter of pair of integers. It forbids pairs with equal elements, like (5,5), with the message "equal". It accepts pairs (x,y) such that x is smaller than y. You just have to define the filter. It will be applied automatically. You don't have to return result values like Accept, Reject or Forbid. Examples if filter f4 is applied to (2,2) ~~> Forbid "equal" if filter f4 applied to (2,3) ~~> Accept if filter f4 applied to (3,2) ~~> Reject ----- Question 5 ★ ----- Open types_filter.ml (with pluma) and read the type definitions (but do NOT copy it in your program). Write a function f5 : ∀ α . α filter → (α option) filter f5 takes a filter g and returns a new filter working on options. None is not forbidden. Some x is forbidden if and only if x is forbidden by g. None is rejected. Some x is accepted if and only if x is accepted by f. Examples In the tests, we use predefined filters, mentionned at the end of types_filter.ml f5 filter_even applied to Some (-5) ~~> Forbid "negative" f5 filter_even applied to Some (5) ~~> Reject f5 filter_even applied to Some (6) ~~> Accept f5 filter_even applied to None ~~> Reject ----- Question 6 ★★ ----- Open types_filter.ml (with pluma) and read the type definitions (but do NOT copy it in your program). Write a function f6 : ∀ α . α filter → (α list) filter f6 takes a filter g working on values of type 'a. It returns a new filter operating on lists of 'a. f6 forbids a list if and only if the list is not empty and all its elements are forbidden by g. In that case, forbid returns the message "all". f6 accepts a list if and only if g accepts at least one element of the list. Examples In the tests, we use predefined filters, mentionned at the end of types_filter.ml f6 filter_even applied to [] ~~> Reject f6 filter_even applied to [-8,-2,-3] ~~> Forbid "all" f6 filter_even applied to [-8,-5,4] ~~> Accept f6 filter_even applied to [3, 8, 7] ~~> Accept f6 filter_even applied to [3, -6, 7] ~~> Reject ----- Question 7 ★★★ ----- Write a function f7 : int → (int × int) list → int list f7 expects a node n and a directed graph. The node n is only a number, e.g. 12. The graph is given as a list of all arcs, e.g. [ (12, 4) ; (12, 3) ] meaning that there are two arcs from node 12 to nodes 3 and 4. The graph may contain loops : (7,7) The graph may contain cycles : (3,6) (6,1) (1,3) f7 must return the list of all nodes that can be reached from node n, including n itself, in any order. For instance, in the cycle above, the nodes [ 3 ; 6 ; 1 ] can be reached from node 3. Nodes must occur at most once in the result. No duplicates. Be careful, this is a graph, your recursion must not loop forever. Examples f7 0 [ ] ~~> 0 f7 1 [ (1, 2) ; (2, 3) ; (3, 4) ; (4, 5) ; (5, 6) ] ~~> [ 1 ; 2 ; 3 ; 4 ; 5 ; 6 ] f7 0 [ (3, 9) ; (4, 2) ; (2, 5) ; (0, 4) ; (4, 9) ] ~~> [ 0 ; 4 ; 9 ; 2 ; 5 ]