IIE - Contrôle IAP1 - Corrigé Vendredi 12 novembre 2004
Transcription
IIE - Contrôle IAP1 - Corrigé Vendredi 12 novembre 2004
IIE - Contrôle IAP1 - Corrigé Vendredi 12 novembre 2004 - durée : 1h30 Sans documents - Calculette sans usage Les exercices sont indépendants. Ne vous bloquez donc pas sur une question. Pour la plupart des exercices, les questions peuvent être traitées même si les questions précédentes ne l’ont pas été. Si nécessaire, vous pouvez utiliser les fonctions min, length, hd (tête d’une liste) et tl (reste d’une liste) sans les redéfinir. De même pour les fonctionnelles étudiées en cours map, fold right, fold left ou filter. Pour répondre à certaines questions, il se peut que vous ayez besoin de définir des fonctions auxiliaires. Dans ce cas indiquez clairement ce que font ces fonctions auxiliaires en donnant par exemple leur interface. Pour les fonctions explicitement demandées dans l’énoncé, n’écrivez leur interface que si celle-ci est explicitement demandée dans l’énoncé. Exercice 1 (Sur 3 points) let rec list_hom e f l = match l with [] -> e | a::r -> f a (list_hom e f r);; let qui_suis_je l = list_hom 0 (+) l;; 1. Quel est le type de la fonction list hom ? 1 point - tout ou rien. Enlever une fois pour toutes 0,5 à ceux qui mettent la réponse de OCaml avec fun. ’a -> (’b -> ’a -> ’a) -> ’b list -> ’a 2. Écrire l’interface de la fonction qui suis je. 2 points - Enlever 0,5 si il manque les tests, 1 point si le type ou la postcondition ne sont pas justes. interface qui_suis_je type : int list -> int arguments l precondition rien postcondition qui_suis_je l retourne la somme des éléments de l tests qui_suis_je [], qui_suis_je [1;2;4] Exercice 2 (Sur 5 points) 1. Ecrire la fonctionnelle takeWhile qui prend 2 arguments : un prédicat p et une liste l et qui retourne la sous-liste préfixe de l composée d’éléments qui vérifient p : takeWhile p [a1; a2 ...an] = [a1; ...ak] (1 ≤ k ≤ n) avec a1, . . . ak éléments qui vérifient p et ak+1 ne vérifie pas p, =[] si a1 ne vérifie pas p. Par exemple, takeWhile (function x -> x mod 2=0) [2; 4; 6; 5; 7; 8; 10] = [2; 4; 6] et takeWhile (function x -> x mod 2=0) [1; 2; 4; 6; 5] = []. 1 point let rec takeWhile p l = match l with [] -> [] | x::r -> if p x then x::(takeWhile p r) else [];; 2. Quel est le type de la fonction takeWhile ? 1 point - tout ou rien (’a -> bool) -> ’a list -> ’a list 1 3. Quel est le type de l’expression takeWhile ((<) 2) ? Si ce type n’existe pas, expliquez brièvement pourquoi l’expression est mal typée. 1 point ou rien int list -> int list 4. Démontrer que pour tout prédicat p et toute liste l, la longueur de takeWhile p l est inférieure ou égale à la longueur de l. Vous rédigerez cette démonstration le plus clairement possible. 2 points - Vérifier que l’élève a bien écrit quel était son principe de récurrence. Attention il y a du mélange. Mettre 0 à ceux qui ne font pas de démonstration mais écrivent ”on voit que”. Exercice 3 (Sur 4 points) Dans cet exercice, on représente en OCaml la matrice a1,1 a1,2 · · · a2,1 a2,2 · · · .. . ap,1 ap,2 ··· a1,n a2,n . ap,n par la liste de listes [[a1,1 ; a1,2 ; · · · a1,n ]; [a2,1 ; a2,2 ; · · · a2,n ]; · · · ; [ap,1 ; ap,2 ; · · · ap,n ]] c’est-à-dire la liste des lignes de la matrice. 1. Définir une fonction transpose qui transpose une matrice représentée par la liste de ses lignes. On supposera que l’argument est une liste de listes qui ont toutes la même longueur. Par exemple la transposition de la matrice représentée par [[1; 2; 3; 4]; [1; 2; 3; 4]; [1; 2; 3; 4]] est la matrice représentée par [[1; 1; 1]; [2; 2; 2]; [3; 3; 3]; [4; 4; 4]]. On remarquera que la première ligne de la transposée est composée des têtes des lignes de la matrice initiale. La fonction transpose devra autant que possible utiliser les fonctionnelles classiques sur les listes comme map, fold right, fold left ou filter. 3 points si la solution utilise les fonctionnelles, 2 si une solution correcte sans fonctionnelle est correcte. Si la solution n’est pas juste, je vous laisse apprécier et donner les points en conséquence entre 0 et 1,5 points. let rec transpose m = match m with | [] -> [] | []::r -> [] | _ -> (List.map List.hd m)::(transpose (List.map List.tl m));; Beaucoup d’éléves ont une solution où manque le cas []::r, d’où échec : dans ce cas j’enlève 1 point. 2. Quel est le type de la fonction transpose ? 1 point, 0,5 si pas polymorphe ’a list list -> ’a list list Exercice 4 (Sur 8 points) Un rationnel est constitué d’un numérateur et d’un dénominateur entiers. On appelle valeur un entier ou un rationnel. 1. Définir le type valeur. 1 point - tout ou rien 2 type rat = {den : int ; num : int};; type valeur = E of int | R of rat;; ou une solution avec des couples pour les rationnels. On souhaite définir des expressions arithmétiques construites à partir de variables munies d’un nom, de nombres munies d’une valeur et de sommes de deux expressions. 2. Définir le type des expressions arithmétiques. 1 point - tout ou rien type arith = Var of string | Const of valeur | Plus of arith * arith;; 3. Représenter l’expression 34 + (y + 3). 1 point - tout ou rien - compter la réponse si le type valeur ne comportait pas de constructeur mais que le reste est bien typé. On considérera comme bien typée l’addition de deux expressions entières ou l’addition de deux expressions rationnelles mais pas l’addition d’une expression rationnelle et d’une expression entière. 4. Définir une fonction type expression qui, à partir d’un environnement (liste de couples associant un nom de variable à une valeur), retourne le type d’une expression. Le cas échéant, cette fonction lève une exception Inconnue paramétrée par le nom de la variable inconnue ou l’exception Mal typé si l’expression est mal typée. Vous commencerez par déclarer ces deux exceptions. Par exemple, dans l’environnement où "x" est associé à la valeur entière nulle, 34 + x est mal typée mais dans l’environnement où "x" est associé à 27 , cette expression est bien typée. Enfin, dans l’environnement vide, le typage de cette expression échoue avec l’exception Inconnue paramétrée par "x". 0,5 point pour la déclaration des exceptions - 2,5 points pour la fonction Sanctionner les copies où aucun commentaire n’est fait sur les fonctions auxiliaires. J’ai l’impression, au vu des copies que j’ai regardées, que les élèves n’ont pas bien compris ce qui était attendu, i.e. un résultat indiquant rationnel ou entier. Accepter les fonctions à résultat dans string. let type_val v = match v with E _ -> Int | R _ -> Rat;; exception Inconnue of string;; exception Mal_typée;; let rec bien_typée a env = match a with Var s -> (try type_val (List.assoc s env ) with Not_found -> raise (Inconnue s)) | Const c -> type_val c | Plus (a1, a2) -> let t1 = bien_typée a1 env and t2 = bien_typée a2 env in if t1 = t2 then t1 else raise Mal_typée;; 5. Définir une fonction évalue qui, à partir d’un environnement (défini comme précédemment), retourne la valeur (de type valeur) résultat de l’évaluation d’une expression supposée bien typée. Par exemple, 29 dans l’environnement où "x" est associé à 27 , 34 + x s’évalue en la valeur qui représente 28 . On ne fera aucune simplification sur les valeurs rationnelles. 2 points 3 let val_plus v1 v2 = match v1, v2 with (E n1, E n2) -> E (n1 + n2) | R {num=n1;den=d1},R {num=n2;den=d2} -> R {den = d1*d2;num = n1*d2 + n2*d1} | _ -> failwith "val_plus";; let rec evalue a env = match a with Var s -> (try (List.assoc s env ) with Not_found -> raise (Inconnue s)) | Const c -> c | Plus (a1, a2) -> let v1 = evalue a1 env and v2 = evalue a2 env in val_plus v1 v2;; 4