Exercices



Les exercices 4, 5, 6, 9, 12 et 13 sont plus importants. Les autres sont davantage destinés à se familiariser avec le langage.



Exercice 1 (Quelques fonctions simples)
1-1. Écrire une fonction prenant un entier x et calculant la valeur de 2x2 + 3x - 2.
1-2. Écrire la fonction entière power telle que power x y calcule xy selon l'algorithme suivant
n0 = 1
n1 = n
np =
ì
í
î
aux2 si p est pair
aux2× n sinon
avec aux = np/2


1-3. Écrire une fonction affichant les (ou rendant la liste des) nombres inférieurs à 1000 et dont la valeur est égale à la somme du cube du chiffre des centaines, du cube du chiffre des dizaines et du cube du chiffre des unités.



Exercice 2 (Représentation et manipulation de matrices)
2-1. Écrire une fonction calculant le produit scalaire de deux vecteurs de taille n.
2-2. Écrire une fonction calculant le produit de deux matrices de taille n × n.



Exercice 3 (Les listes simples, filtrage et itérateurs)
3-1. Écrire une fonction retournant le deuxième élément d'une liste.
3-2. Écrire une fonction sommant les valeurs contenues dans une liste d'entiers.
3-3. Écrire une fonction affichant tous les éléments d'une liste d'entiers.
3-4. Écrire une fonction incrémentant d'une valeur entière, passée en paramètre, tous les éléments d'une liste d'entiers.
3-5. Écrire une fonction incrémentant d'une valeur entière, passée en paramètre, toutes les premières composantes d'une liste de couples d'entiers.
3-6. Écrire une fonction qui prend en argument une liste de couples et retourne la liste de leur première composante.
3-7. Écrire une fonction incrémentant d'une valeur entière, passée en paramètre, tous les premiers éléments d'une liste de listes d'entiers. Que se passe-t-il lorsque l'on passe une liste d'entiers en argument ? Et une liste de listes de listes d'entiers ?



Exercice 4 (Exceptions)

Que répond Caml aux phrases suivantes:
    exception pas_grave of int;;
    exception grave of string;;
    let pseudo_id x =
       if (x < 0) then raise (pas_grave (-x))
       else if (x = 0) then raise (grave "Argh !!!") else x ;;
    pseudo_id(-4);;
    pseudo_id(0);;
    pseudo_id(2);;
    let f = let val = 10 in function x ->
       try let val = 100 in pseudo_id(x) - val with
          | pas_grave n -> if (n < 0) then raise(grave "impossible ?") else n + val
          | grave "Argh !!!" -> raise(pas_grave(10))
          | grave s -> raise(grave "possible ?");;
    f(-100);;
    f(0);;
    f(100);;
    f(grave "Ouf !!!");;
    f(raise(grave "Ouf !!!"));;




Exercice 5 (Itérateurs classiques sur les listes)
5-1. Écrire la fonction it_list de Caml Light (fold_left en Objective Caml), de type
('a -> 'b -> 'a) -> 'a -> 'b list -> 'a telle que it_list f a [b1; ...; bn] correspond à f (... (f (f a b1) b2) ...) bn.


5-2. Écrire la fonction list_it de Caml Light (fold_right en Objective Caml), de type
('a -> 'b -> 'b) -> 'a list -> 'b -> 'b telle que list_it f [a1; ...; an] b correspond à f a1 (f a2 (... (f an b) ...)).



Exercice 6 (Itérateurs map et do_ sur les arbres binaires)
6-1. Définir un type 'a tree d'arbres binaires
6-2. Définir la fonction print_tree_prefix qui imprime un arbre par un parcours préfixe.
6-3. Écrire l'itérateur map_tree, ainsi que do_tree_infix. En déduire la fonction print_tree_infix.
6-4. Définir la fonction tree_list qui rend la liste correspondant au parcours infixe de l'arbre.
6-5. Écrire la fonction insert_tree qui insère un élément dans un arbre binaire de recherche.
6-6. En déduire sans utiliser les itérateurs list_it et it_list la fonction tree_sort_list qui trie une liste en utilisant un arbre binaire de recherche.
6-7. Exprimer cette fonction à l'aide de l'itérateur list_it vu dans l'exercice précédent.
6-8. Redéfinir la fonction d'insertion d'un élément dans un arbre de telle sorte que la fonction tree_sort_list s'écrive aisément à l'aide de l'itérateur it_list vu dans l'exercice précédent.



Exercice 7 (Utilisation des listes pour une version naïve du crible d'Eratosthene, de la factorisation d'entiers et calcul du pgcd)

Pour bon nombre de ces fonctions, on pourra utiliser des itérateurs.
7-1. Écrire la fonction ote_multiples qui supprime tous les diviseurs de n de la liste l.
7-2. Écrire la fonction ote_diviseurs qui supprime tous les nombres qui ne divisent pas n de la liste l.
7-3. Écrire la fonction interval qui retourne la liste des entiers compris entre i et j. Votre fonction termine-t-elle toujours?
7-4. Écrire une fonction Eratosthene qui retourne la liste des nombres premiers inférieurs à n en vous aidant des fonctions ote_multiples et interval.

En déduire la fonction liste_diviseurs_premiers qui retourne la liste des diviseurs premiers de n.
7-5. Écrire la fonction power_m_in_n qui retourne la plus grande puissance de m qui divise n.

En déduire la fonction liste_diviseurs qui à partir de la liste triée des diviseurs premiers de n calcule la liste triée de tous les diviseurs premiers de n avec leur exposants respectifs.
7-6. En supposant que les listes l1 et l2 représentent la liste triée par ordre croissant des couples (diviseur_premier, exposant) des nombres n1 et n2, écrire la fonction power_min qui calcule la liste des diviseurs premiers qui divisent n1 et n2 avec le plus grand exposant possible.
7-7. Écrire la fonction prod qui calcule le produit des éléments d'une liste.
7-8. En utilisant la fonction power écrite la semaine dernière et ce qui précède, en déduire la fonction pgcd qui calcule le plus grand commun diviseur de deux entiers.



Exercice 8 (Comment utiliser les itérateurs pour réaliser un crible d'Ératosthène)

Dans la lignée de l'exercice précédent, nous considérons ici une version utilisant des itérateurs et même, n'ayons peur de rien, es itérateurs appliqués à des itérateurs.
8-1. Écrire l'itérateur filter tel que filter p l est la sous-liste des éléments de la liste l qui vérifient le prédicat p.
8-2. Écrire la fonction pseudo_non_multiple telle que pseudo_non_multiple n m rend vrai si m=n ou si m n'est pas divisible par n.
8-3. En déduire la fonction pseudo_non_multiples_liste qui à n associe la liste des fonctions pseudo_non_multiple i pour i allant de 2 à n.
8-4. Écrire la fonction liste_n qui construit la liste des entiers de 2 à n.
8-5. En utilisant les itérateurs list_it et filter en déduire la fonction liste_premiers telle que liste_premiers n donne la liste des nombres premiers compris entre 1 et n.



Exercice 9 (Typage, ordre supérieur, fonctions anonymes)


9-1. Écrire les fonctions curry : ('a * 'b -> 'c) -> 'a -> 'b -> 'c et uncurry : ('a -> 'b -> 'c) -> 'a * 'b -> 'c qui permettent de transformer une fonction à deux arguments en une fonction à un seul argument couple et inversement.
9-2. On rappelle le type de la fonction compose : ('a -> 'b) -> ('c -> 'a) -> 'c -> 'b.

Pour chacune des expressions suivantes, vous indiquerez son type ainsi qu'une fonction anonyme sémantiquement équivalente: uncurry compose, compose curry uncurry et compose uncurry curry.



Exercice 10 (La date du lendemain: découpage d'un problème)

On souhaite déterminer la date du lendemain, c'est-à-dire définir une fonction lendemain qui prend en argument une date d et calcule la date correspondant au lendemain du jour décrit par la date d. On représente une date par un triplet de 3 entiers (ou un enregistrement) (jour, mois, année).

Il convient de s'assurer que le triplet (jour, mois, année), argument de la fonction, correspond à une date valide c'est-à-dire que mois est un entier entre 1 et 12, que jour est un entier compris entre 1 et le nombre de jours de mois en tenant compte des années bissextiles.

On ne s'intéresse qu'aux dates du calendrier grégorien c'est-à-dire au delà du 15 octobre 1582. Depuis cette date, une année est bissextile si elle est un multiple de 400 ou un multiple de 4 qui n'est pas un multiple de 100.



Exercice 11 (Les légumes: structures de données)

L'état du rayon « légumes » d'un supermarché est tenu à jour par l'ordinateur central d'après les informations fournies par les caisses.

Chaque légume est représenté par son nom, la quantité présente en rayon, le seuil à partir duquel il faut réapprovisionner le rayon, ainsi que son prix. La quantité peut être soit un nombre de pièces (par 2 céleris), soit un nombre de kilos (par exemple 1.5 kilo de carottes). Selon les saisons les légumes varient et sont plus ou moins nombreux.


11-1. (Types)

Définissez le type légume. Pour cela vous pouvez définir tous les types intermédiaires que vous souhaitez. Indiquez la représentation des tomates, à 5,50 francs le kilo, avec 20 kilos en rayon et un seuil de commande de 5 kilos.


11-2. (Quantités)
11-3. (Panier)

Une ménagère achète des légumes pour son pot au feu: quelques carottes, des pommes de terre, une botte de poireaux, un oignon, un bouquet d'herbes. Par quelle structure de données représentez-vous le panier de cette ménagère?


11-4. (Prix)
11-5. (Mise à jour)
11-6. (Commande)

Écrire une fonction légumes_à_commander qui compose la commande après mise à jour du stock du rayon r.



Exercice 12 (Définir soi-même les listes)


12-1. Définissez le type des listes d'entiers.
12-2. Écrivez (définir, typer et évaluer) les fonctions suivantes : Dans la suite on donnera les solutions pour ce type en définissant ses propres fonctions puis pour le type prédéfini des listes en s'appuyant sur la bibliothèque disponible en Caml.
12-3. Écrivez la fonction merge qui fusionne deux listes triées. En déduire une fonction de tri par dichotomie.



Exercice 13 (Arbres d'expression (évaluation, simplification))

On considère les formules du calcul propositionnel obtenues à partir des formules atomiques (Pi)i Î IN et des connecteurs usuels Ù (« et »), Ú (« ou »), ¬ (« non »), Þ (« implique ») et ÜÞ (« équivalent à »).

On rappelle les lois de Morgan de distibutivité de Ù et Ú l'un par rapport à l'autre:
F1 Ù (F2 Ú F3) º (F1 Ù F2) Ú (F1 Ù F3)
F1 Ú (F2 Ù F3) º (F1 Ú F2) Ù (F1 Ú F3)
De même,
¬ (F1 Ù F2) º ¬ F1 Ú ¬ F2
¬ (F1 Ú F2) º ¬ F1 Ù ¬ F2

13-1. Définissez un type Caml pour représenter ces formules. Donnez la représentation des formules suivantes :
P1,  (¬ P1),  (P1 ÙP2)),  (¬ (P1 Þ P2)),  ((¬ P1) ÜÞ P2), ((P1 Þ P2) ÜÞ ¬ ((¬ P1) ÚP2))).

13-2. Écrire une fonction string_of_formule: formule -> string qui imprime une formule. Par exemple, on pourra utiliser \/ pour le connecteur Ú, /\ pour le connecteur Ù, => pour le connecteur Þ , <=> pour le connecteur ÜÞ et ! pour le connecteur ¬.
13-3. On rappelle que si F1 et F2 sont deux formules propositionnelles, F1 Þ F2 ºF1) Ú F2 et F1 ÜÞ F2 º (F1 Ù F2) Ú ((¬ F1) ÙF2)).

Écrire une fonction normalize qui transforme une formule avec les connecteurs Þ et ÜÞ en une formule équivalente sans ces connecteurs.
13-4. Écrire une fonction liste_variables: formule -> int list qui détermine la liste des variables d'une formule. Chaque variable ne devra apparaître qu'une seule fois. Vous écrirez cette fonction à l'aide de la fonction de la bibliothèque standard union: 'a list -> 'a list -> 'a list. Vous en écrirez ensuite une autre version utilisant un accumulateur et la fonction mem: 'a -> 'a list -> bool.
13-5. Écrire une fonction éval: (int * bool) list -> formule -> bool qui compte tenu de la valeur des variables qui apparaissent dans une formule détermine la valeur de vérité de la formule. Par exemple, éval [(1,true); (2,true)] (Ou (Var 1, Var 2)) rendra la valeur true. Vous déclencherez une exception, que vous définirez, lorsque la formule contient une variables qui n'est pas dans la liste.
13-6. Écrire une version fonctionnelle de la fonction éval qui prenne en argument une fonction de type int -> bool au lieu d'une liste d'associations.
13-7. Écrire une fonction substituer: formule -> int -> formule -> formule telle que substituer F i v retourne la formule obtenue en substituant à la variable d'indice i la formule v dans la formule F.
13-8. Écrire une fonction substitue_fun: (int -> formule) -> formule -> formule telle que substitue_fun f F est la formule obtenue en substituant toutes les occurences de Var i dans F par f i.
13-9. Écrire une fonction éval_sans_var : formule -> bool qui évalue une formule sans variables, vous déclencherez une exception que vous définirez lorsque la formule contient des variables. En déduire une autre version de la fonction éval précédente qui utilise substituer.

Nous allons à présent écrire deux versions de la fonction est_tautologie qui teste si une formule est une tautologie, c'est-à-dire si la valeur de vérité de cette formule est true quelle que soit la valeur des variables qu'elle contient.

Chaque ligne de la table de vérité est décrite par la liste d'associations formée des couples (nom_de_variable, valeur). Par exemple, pour la formule P1 Ú P2, la première ligne est décrite par [(1,true); (2,true)].
13-10. Écrire une fonction énumération_cas_liste qui énumère toutes les tables d'associations correspondant à toutes les lignes de la table de vérité d'une formule.
13-11. En déduire une première version de la fonction est_tautologie.


13-12. (Algorithme de Shannon)

L'algorithme de Shannon pour tester si une formule est une tautologie est le suivant: pour déterminer si une formule F contenant les variables v1, ... vn est une tautologie nous allons créer deux formules Ft et Ff obtenues en substituant v1 respectivement à Vrai et Faux et déterminer si Ft et Ff qui contiennent alors les variables v2, ... vn sont des tautologies. Nous utiliserons la fonction éval_sans_var précédente lorsque la formule ne contient pas de variables.

Écrire une fonction est_tautologie : formule -> int list -> bool qui vérifie si une formule F contenant au plus les variables de la liste l est une tautologie.


This document was translated from LATEX by HEVEA.