diff --git a/td/lifpf-td2-correction.pdf b/td/lifpf-td2-correction.pdf new file mode 100644 index 0000000000000000000000000000000000000000..76adc698deda312b494ae20dcad36360876d295c Binary files /dev/null and b/td/lifpf-td2-correction.pdf differ diff --git a/td/lifpf-td3-correction.pdf b/td/lifpf-td3-correction.pdf new file mode 100644 index 0000000000000000000000000000000000000000..3a06b3161c647cf0411c3c374f3a1461b7bde27a Binary files /dev/null and b/td/lifpf-td3-correction.pdf differ diff --git a/td/lifpf-td4-correction.pdf b/td/lifpf-td4-correction.pdf new file mode 100644 index 0000000000000000000000000000000000000000..60243a514d43edf76c38532b851e5aabf580fd09 Binary files /dev/null and b/td/lifpf-td4-correction.pdf differ diff --git a/tp/tp3.ml b/tp/tp3.ml new file mode 100644 index 0000000000000000000000000000000000000000..7599c79c9c140802121dd6c1eb4e794553a41325 --- /dev/null +++ b/tp/tp3.ml @@ -0,0 +1,214 @@ +(* LIFPF TP3 Récursion sur les arbres *) + +(**********************************************************************) +(* Arbres binaires *) +(**********************************************************************) + +(** +Arbres binaires avec feuilles vides, +le contenu est seulement sur les noeuds. +*) +type arbre_bin = ABVide | ABNoeud of int * arbre_bin * arbre_bin + +(* Quelques arbres pour tester *) +let ab1 = ABNoeud (3, ABVide, ABVide) +let ab2 = ABNoeud (5, ab1, ABVide) +let ab3 = ABNoeud (7, ABVide, ab1) +let ab4 = ABNoeud (11, ab2, ab3) + +(** +Taille d'un arbre binaire. +@param a l'arbre dont on veut calculer la taille +@return le nombre d'int stockés dans l'arbre +*) +let rec taille_ab (a : arbre_bin) : int = + match a with + | ABVide -> 0 + | ABNoeud (_, fg, fd) -> 1 + taille_ab fg + taille_ab fd +;; + +assert (taille_ab ab1 = 1);; +assert (taille_ab ab2 = 2);; +assert (taille_ab ab3 = 2);; +assert (taille_ab ab4 = 5) + +(** +Fait le produit des éléments d'un arbre binaire. +Un arbre vide aura 1 comme produit +@param a l'arbre dont on veut faire le produit des éléments +@return le produit (1 pour l'arbre vide) +*) +let rec produit_ab (a : arbre_bin) : int = + match a with + | ABVide -> 1 + | ABNoeud (n, fg, fd) -> n * produit_ab fg * produit_ab fd +;; + +assert (produit_ab ABVide = 1);; +assert (produit_ab ab1 = 3);; +assert (produit_ab ab2 = 15);; +assert (produit_ab ab3 = 21);; +assert (produit_ab ab4 = 3465) + +(** +Construit la liste des éléments d'un arbre binaire. Les éléments sont produits +dans l'ordre de parcours infix, c'est à dire les éléments du fils gauche puis +l'élément du noeud puis ceux fils droit. + +@param a l'arbre binaire dont on veut les éléments +@return la liste des éléments de l'arbre +*) +let rec list_of_arbre_bin (a : arbre_bin) : int list = + match a with + | ABVide -> [] + | ABNoeud (n, fg, fd) -> + (* On peut aussi utiliser la fonction concatene du TP2 *) + list_of_arbre_bin fg @ (n :: list_of_arbre_bin fd) +;; + +assert (list_of_arbre_bin ABVide = []);; +assert (list_of_arbre_bin ab1 = [ 3 ]);; +assert (list_of_arbre_bin ab2 = [ 3; 5 ]);; +assert (list_of_arbre_bin ab3 = [ 7; 3 ]);; +assert (list_of_arbre_bin ab4 = [ 3; 5; 11; 7; 3 ]) + +(** +Insère un élément dans un arbre binaire de recherche. + +@param e l'élément à insérer +@param a l'arbre dans lequel on fait l'insersion +@return un arbre binaire de recherche contenant les éléments de a ainsi que e +*) +let rec insere_arbre_bin_recherche (e : int) (a : arbre_bin) : arbre_bin = + match a with + | ABVide -> ABNoeud (e, ABVide, ABVide) + | ABNoeud (x, fg, fd) -> + if e < x then ABNoeud (x, insere_arbre_bin_recherche e fg, fd) + else ABNoeud (x, fg, insere_arbre_bin_recherche e fd) + +let abr1 = insere_arbre_bin_recherche 7 ABVide +let abr2 = insere_arbre_bin_recherche 5 abr1 +let abr3 = insere_arbre_bin_recherche 3 abr2 +let abr4 = insere_arbre_bin_recherche 11 abr3;; + +assert (list_of_arbre_bin abr1 = [ 7 ]);; +assert (list_of_arbre_bin abr2 = [ 5; 7 ]);; +assert (list_of_arbre_bin abr3 = [ 3; 5; 7 ]);; +assert (list_of_arbre_bin abr4 = [ 3; 5; 7; 11 ]) + +(** +Créée un arbre binaire de recherche contenant les éléments de la liste + +@param l la liste contenant les éléments à placer dans l'arbre à créer +@return l'arbre binaire de recherche contenant les éléments de l +*) +let rec arbre_bin_rech_of_int_list (l : int list) : arbre_bin = + match l with + | [] -> ABVide + | x :: l' -> insere_arbre_bin_recherche x (arbre_bin_rech_of_int_list l') +;; + +assert (list_of_arbre_bin (arbre_bin_rech_of_int_list []) = []);; +assert (list_of_arbre_bin (arbre_bin_rech_of_int_list [ 3 ]) = [ 3 ]);; +assert (list_of_arbre_bin (arbre_bin_rech_of_int_list [ 3; 5 ]) = [ 3; 5 ]);; +assert (list_of_arbre_bin (arbre_bin_rech_of_int_list [ 5; 3 ]) = [ 3; 5 ]);; + +assert ( + list_of_arbre_bin (arbre_bin_rech_of_int_list [ 1; 2; 3; 4 ]) = [ 1; 2; 3; 4 ]) +;; + +assert ( + list_of_arbre_bin (arbre_bin_rech_of_int_list [ 4; 2; 1; 3 ]) = [ 1; 2; 3; 4 ]) + +(** +Trie une list d'int en utilisant un arbre binaire de recherche + +@param l la liste à trier +@return la liste triée +*) +let tri_abr (l : int list) : int list = + list_of_arbre_bin (arbre_bin_rech_of_int_list l) +;; + +assert (tri_abr [] = []);; +assert (tri_abr [ 3 ] = [ 3 ]);; +assert (tri_abr [ 3; 5 ] = [ 3; 5 ]);; +assert (tri_abr [ 5; 3 ] = [ 3; 5 ]);; +assert (tri_abr [ 1; 2; 3; 4 ] = [ 1; 2; 3; 4 ]);; +assert (tri_abr [ 4; 2; 1; 3 ] = [ 1; 2; 3; 4 ]) + +(**********************************************************************) +(* Expressions arithmétiques et variables *) +(**********************************************************************) + +(** +Type représentant les opérateurs binaires. +*) +type binop = Plus | Moins | Mult | Div + +(** +Expressions arithmétiques + let +*) +type expr = + | Cst of int + | Binop of binop * expr * expr + | Var of string + | Let of string * expr * expr + +(** affichage **) +let rec string_of_expr (e : expr) : string = + let string_of_binop (b : binop) = + match b with Plus -> " + " | Moins -> " - " | Mult -> " * " | Div -> " / " + in + + match e with + | Cst n -> string_of_int n + | Binop (op, l, r) -> + "(" ^ string_of_expr l ^ string_of_binop op ^ string_of_expr r ^ ")" + | Var x -> x + | Let (v, e1, e2) -> + "(let " ^ v ^ " = " ^ string_of_expr e1 ^ " in " ^ string_of_expr e2 ^ ")" + +(** Erreurs *) +type eval_err = DivZero | VarNonDef + +(** Résultats: int ou erreur *) +type resultat = Ok of int | Err of eval_err + +(** +Évalue une expression dans un environnement +*) +let rec eval_expr (e : expr) (env : (string * int) list) : resultat = + match e with + | Cst n -> Ok n + | Binop (op, e1, e2) -> ( + match (eval_expr e1 env, eval_expr e2 env) with + | Ok v1, Ok v2 -> ( + match op with + | Plus -> Ok (v1 + v2) + | Moins -> Ok (v1 - v2) + | Mult -> Ok (v1 * v2) + | Div -> if v2 = 0 then Err DivZero else Ok (v1 / v2)) + | Err e, _ -> Err e + | _, Err e -> Err e) + | Var x -> ( + match List.assoc_opt x env with None -> Err VarNonDef | Some n -> Ok n) + | Let (x, e1, e2) -> ( + match eval_expr e1 env with + | Ok v1 -> eval_expr e2 ((x, v1) :: env) + | Err e -> Err e) + +let e1 = Cst 3 +let e2 = Binop (Plus, Cst 3, Cst 5) +let e3 = Binop (Div, Cst 3, Cst 0) +let e4 = Let ("a", Cst 3, Binop (Moins, Var "a", Cst 3)) +let e5 = Let ("a", Cst 3, Var "b");; + +assert (eval_expr e1 [] = Ok 3);; +assert (eval_expr e2 [] = Ok 8);; +assert (eval_expr e3 [] = Err DivZero);; +assert (eval_expr e4 [] = Ok 0);; +assert (eval_expr e5 [] = Err VarNonDef);; +assert (eval_expr e5 [ ("b", 11) ] = Ok 11) + +(**********************************************************************) diff --git a/tp/tp4.ml b/tp/tp4.ml new file mode 100644 index 0000000000000000000000000000000000000000..2bf80016a6015e5717e65c667ccd4bd3365ca77b --- /dev/null +++ b/tp/tp4.ml @@ -0,0 +1,240 @@ +(**********************************************************************) +(* Arbres n-aires *) +(**********************************************************************) +(** Arbre avec un nombre quelconque de fils *) +type 'a arbre_n = Feuille of 'a | Noeud of 'a arbre_n list + +let a1 = Feuille 1 +let a2 = Feuille 2 +let a3 = Noeud [] +let a4 = Noeud [ a1 ] +let a5 = Noeud [ a1; a2 ] +let a6 = Noeud [ a1; a2; a3; a4; a5 ] +let a_vide_1 = Noeud [] +let a_vide_2 = Noeud [ Noeud [] ] +(* Le type de ces arbres vide est 'a arbre_n. En effet, comme ces arbres ne + contiennent pas d'éléments ils peuvent être vus comme des arbresavec ce qu'on + veut comme type d'élément. *) + +let rec hauteur (a : 'a arbre_n) : int = + match a with Feuille _ -> 1 | Noeud l -> hauteur_foret l + 1 + +and hauteur_foret (l : 'arbre_n list) : int = + match l with + | [] -> 0 + | a :: l' -> max (hauteur a) (hauteur_foret l') +;; + +assert (hauteur a1 = 1);; +assert (hauteur a3 = 1);; +assert (hauteur a4 = 2);; +assert (hauteur a5 = 2);; +assert (hauteur a6 = 3) + +(** +Renvoie une liste contenant tous les éléments de l'arbre + +@param a: l'arbre +@return la liste de ses éléments +*) +let list_of_arbre (a : 'a arbre_n) : 'a list = + let rec list_of_arbre_aux (a : 'a arbre_n) (acc : 'a list) : 'a list + = + match a with + | Feuille x -> x :: acc + | Noeud f -> list_of_foret f acc + and list_of_foret (f : 'a arbre_n list) (acc : 'a list) : 'a list = + match f with + | [] -> acc + | a :: f' -> list_of_arbre_aux a (list_of_foret f' acc) + in + list_of_arbre_aux a [] +;; + +assert (list_of_arbre a1 = [ 1 ]);; +assert (list_of_arbre a4 = [ 1 ]);; +assert (list_of_arbre a5 = [ 1; 2 ]);; +assert (list_of_arbre a6 = [ 1; 2; 1; 1; 2 ]) + +(** +[minimum arbre] est le plus grand élément de arbre si arbre en contient au moins 1. + +@param arbre l'arbre dans lequel on cherche le minimum +@return None si l'arbre ne contient pas d'élément, ou sinon Some m avec m le plus petit élément de l'arbre +*) +let rec minimum (arbre : 'a arbre_n) : 'a option = + match arbre with + | Feuille x -> Some x + | Noeud la -> minimum_foret la + +(** +[minimum_foret l] donne l'élément minimal que l'on peut trouver dans une forêt + +@param l la forêt +@return None si la forêt ne contient pas d'élément ou sinon Some m où m est le plus petit élément de la forêt +*) +and minimum_foret (la : 'a arbre_n list) : 'a option = + match la with + | [] -> None + | a :: la' -> ( + match minimum_foret la' with + | None -> minimum a + | Some n -> ( + match minimum a with + | None -> Some n + | Some n' -> Some (min n n'))) +;; + +assert (minimum a1 = Some 1);; +assert (minimum a3 = None);; +assert (minimum a4 = Some 1);; +assert (minimum a5 = Some 1);; +assert (minimum a6 = Some 1) + +(** +[reduce f a] renvoie: +- None si a ne contient aucun élément +- Some x si a contient un seul élément x +- Some x où x est le résultat de la combinaison des éléments de a en utilisant f + +@param f la fonction de combinaison des éléments +@param a l'arbre qui contient les éléments +*) +let rec reduce (f : 'a -> 'a -> 'a) (arbre : 'a arbre_n) : 'a option = + match arbre with Feuille x -> Some x | Noeud l -> reduce_foret f l + +(** +[reduce_foret f l] renvoie: +- None si l (en tant que forêt) ne contient aucun élément +- Some x si l contient un seul élément x +- Some x où x est le résultat de la combinaison des éléments de l en utilisant f + +@param f la fonction de combinaison des éléments +@param la forêt qui contient les éléments +*) +and reduce_foret (f : 'a -> 'a -> 'a) (la : 'a arbre_n list) : + 'a option = + match la with + | [] -> None + | a :: la' -> ( + match reduce_foret f la' with + | None -> reduce f a + | Some n -> ( + match reduce f a with + | None -> Some n + | Some n' -> Some (f n n'))) +;; + +assert (reduce min a1 = Some 1);; +assert (reduce min a3 = None);; +assert (reduce min a4 = Some 1);; +assert (reduce min a5 = Some 1);; +assert (reduce min a6 = Some 1);; +assert (reduce ( + ) a1 = Some 1);; +assert (reduce ( + ) a3 = None);; +assert (reduce ( + ) a5 = Some 3);; +assert (reduce ( + ) a6 = Some 7) + +(**********************************************************************) +(* Files (FIFO) implémentées avec deux listes *) +(**********************************************************************) + +type 'a fifo = Fifo of ('a list * 'a list) + +(** File vide *) +let empty_fifo : 'a fifo = Fifo ([], []) + +(** +[push_fifo e f] Ajoute e dans f + +@param e l'élément a ajouter +@param f la fifo dans laquelle on veut ajouter l'élément +@return la fifo contenant les éléments de f puis e +*) +let push_fifo (e : 'a) (f : 'a fifo) : 'a fifo = + match f with Fifo (l1, l2) -> Fifo (e :: l1, l2) + +let f1 = push_fifo 1 empty_fifo +let f2 = push_fifo 2 f1 +let f3 = push_fifo 3 f2 +let f4 = push_fifo 4 f3;; + +assert (f1 = Fifo ([ 1 ], []));; +assert (f2 = Fifo ([ 2; 1 ], []));; +assert (f3 = Fifo ([ 3; 2; 1 ], []));; +assert (f4 = Fifo ([ 4; 3; 2; 1 ], [])) + +(** +[push_list_fifo l f] ajoute les éléments de l à la file f + +@param l les éléments à ajouter +@param f la file dans laquelle ajouter les éléments +@return la file contenant les éléments de f puis les éléments de l +*) +let rec push_list_fifo (l : 'a list) (f : 'a fifo) : 'a fifo = + match l with + | [] -> f + | x :: l' -> push_list_fifo l' (push_fifo x f) +;; + +assert (push_list_fifo [] empty_fifo = empty_fifo);; +assert (push_list_fifo [] f2 = f2);; +assert (push_list_fifo [ 1 ] empty_fifo = f1);; +assert (push_list_fifo [ 3; 4 ] f2 = f4);; +assert (push_list_fifo [ 1; 2; 3; 4 ] empty_fifo = f4) + +(** +Fonction utilitaire transférant tous les éléments de la liste de gauche dans +celle de droite en en renversant l'ordre au passage. +*) +let rec transfert_fifo (f : 'a fifo) : 'a fifo = + match f with + | Fifo ([], l2) -> Fifo ([], l2) + | Fifo (x :: l1, l2) -> transfert_fifo (Fifo (l1, x :: l2)) +;; + +assert (transfert_fifo f4 = Fifo ([], [ 1; 2; 3; 4 ]));; +assert (transfert_fifo f1 = Fifo ([], [ 1 ])) + +(** +[pop_fifo f] renvoie le premier élément de f s'il y en a un, ainsi que la file contenant le reste des éléments de f. + +@param f la file dans laquelle on veut prendre un élément +@return (f',r) où +- f' est la file contenant les éléments de f sauf le premier +- r est Some x si f a pour premier élément x ou bien None si f est vide +*) +let pop_fifo (f : 'a fifo) : 'a fifo * 'a option = + match f with + | Fifo (l1, []) -> ( + match transfert_fifo f with + | Fifo (_, []) -> (Fifo ([], []), None) + | Fifo (_, x :: l2') -> (Fifo ([], l2'), Some x)) + | Fifo (l1, x :: l2') -> (Fifo (l1, l2'), Some x) +;; + +assert (pop_fifo empty_fifo = (empty_fifo, None));; +assert (pop_fifo f1 = (empty_fifo, Some 1));; +assert (pop_fifo f2 = (Fifo ([], [ 2 ]), Some 1));; +assert (pop_fifo (fst (pop_fifo f2)) = (empty_fifo, Some 2)) + +(** +Renvoie tous les éléments de la file dans l'ordre de celle-ci + +@param f la file dont on veut les éléments +@return une liste contenant les éléments de f dans l'ordre +*) +let rec pop_all_fifo (f : 'a fifo) : 'a list = + match pop_fifo f with + | _, None -> [] + | f', Some x -> x :: pop_all_fifo f' +;; + +assert (pop_all_fifo empty_fifo = []);; +assert (pop_all_fifo f1 = [ 1 ]);; +assert (pop_all_fifo f4 = [ 1; 2; 3; 4 ]);; + +(* Un test mélangeant les opérations de push et de pop de la file *) +assert ( + pop_all_fifo (push_list_fifo [ 3; 4 ] (fst (pop_fifo f2))) + = [ 2; 3; 4 ])