=======================================================================================
=== ===
=== 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 : ∀ α β . (α → β) → (α → β)
This is about exceptions. These exceptions already exist in standard Ocaml:
- exception Invalid_argument of string e.g. Invalid_argument "this is baaaaad!"
- exception Failure of string e.g. Failure "this is also baaaaad!"
f1 expects a function g. It returns a new function g2 such that :
- g2 behaves exactly like g, but
- if g raises the exception Failure, then g2 raises the exception Invalid_argument with the same string
- if g raises the exception Invalid_argument, then g2 raises the exception Failure with the same string
In short, g2 is like g, but the exceptions Invalid_argument and Failure have been switched.
Examples
f1 (fun () -> 0) () ~~> 0
f1 (fun () -> raise Not_found) () ~~> fails with Not_found
f1 (fun () -> raise (Failure "toto")) () ~~> fails with Invalid_argument "toto"
f1 (fun () -> raise (Invalid_argument "zaza")) () ~~> fails with Failure "zaza"
----- Question 2 ★★ -----
Write a function f2 : ∀ α . α → α → α list → α list
f2 expects three arguments: x, y, and a list l.
f2 must return the part of the list l which is between x and y.
More precisely :
- if x does not occur in the list l, return the empty list.
- if x occurs in l, return the part of the list 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 x until the end.
Examples
let l = [ 1 ; 2 ; 3 ; 3 ; 4 ; 5 ; 6 ; 7 ] (* Notice: 3 occurs twice. *)
f2 9 5 l ~~> []
f2 5 5 l ~~> [ 5 ; 6 ; 7 ]
f2 3 5 l ~~> [ 3 ; 3 ; 4 ; 5 ]
f2 3 0 l ~~> [ 3 ; 3 ; 4 ; 5 ; 6 ; 7 ]
f2 3 3 l ~~> [ 3 ; 3 ]
f2 5 5 l ~~> [ 5 ; 6 ; 7 ]
f2 1 3 l ~~> [ 1 ; 2 ; 3 ]
----- 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 → α list
f2 expects a tree (as defined in Types_tree).
f2 must return the list of values found in the tree, in any order.
Examples
Take a look at test tree number 4304:
q3_qvalue 4304 ;; (* A tree with six nodes should be printed (assuming I have the same tree than you). *)
Its values are [ -13 ; 0 ; 3 ; 0 ; -3 ; 1 ]
Then, you can directly test your function with
q3_invok f3 4304 ;;
Another test: (q3_qvalue 1702) has 8 nodes : [ -8 ; 4 ; 2 ; 0 ; -1 ; -3 ; 0 ; -1 ]
----- 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 option) filter
f4 is a filter of options of integers.
It forbids only one value : Some 0, with the message "zero".
It accepts only values of the form Some x where x is positive.
It rejects None and Some x where x is negative.
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 Some 0 ~~> Forbid "zero"
if filter f4 applied to Some 1 ~~> Accept
if filter f4 applied to None ~~> 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 → (β×α) filter
f5 takes a filter g working on pairs and returns a new filter also working on pairs.
(a,b) is forbidden by f5 if and only if (b,a) is forbidden by g.
(a,b) is accepted by f5 if and only if (b,a) is accepted by g.
Examples
In the tests, we use predefined filters, mentionned at the end of types_filter.ml
f5 filter_pair applied to (-5,0) ~~> Reject
f5 filter_pair applied to (0,-5) ~~> Forbid "negative"
f5 filter_pair applied to (2,2) ~~> Accept
----- 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 contains at least one element forbidden by g.
Then, it returns the message associated to the first forbidden element in the list
f6 accepts a list if and only if g accepts all the elements of the list.
Examples
In the tests, we use predefined filters, mentionned at the end of types_filter.ml
f6 filter_even applied to [] ~~> Accept
f6 filter_even applied to [8,2,-3] ~~> Forbid "negative"
f6 filter_even applied to [8,2,4] ~~> Accept
f6 filter_even applied to [8,2,5] ~~> 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 ]