TD 5 - LRI
Transcription
TD 5 - LRI
Université Paris Sud L3, S5 Info311 - Programmation fonctionnelle avancée 2016-2017 TD 5 – 1 Exceptions : variations autour de la multiplication On considère évidemment pour cette partie que la liste manipulée n’est pas originellement vide Exercice 1 Implémenter de façon naı̈ve une fonction mult : int list -> int qui renvoie le résultat de la multiplication de tous les éléments d’une liste. Exercice 2 Réécrire cette fonction en gérant le cas où un des éléments de la liste est égal à zéro. Exercice 3 Modifier cette fonction en utilisant une exception. A priori cette fonction n’est pas récursive terminale. La modifier afin qu’elle le soit. Exercice 4 Écrire une dernière version utilisant List.fold left mais qui s’arrête si un 0 est rencontré. List.assoc Exercice 5 Implémenter à l’aide d’un itérateur la fonction assoc_int : ’a -> (’a * int) list -> int telle que assoc int k l renvoie la valeur associée à k dans l si celle-ci existe et Not found sinon. Exercice 6 Implémenter à l’aide d’un itérateur la fonction assoc : ’a -> (’a * ’b) list -> ’b telle que assoc k l renvoie la valeur associée à k dans l si celle-ci existe et Not found sinon. 2 Files à changement de priorité Le but de ces exercides est de développer une structure de données pour représenter une file de priorité sur laquelle on peut effectuer les trois opérations suivantes : — ajouter un élément dans la file avec une certaine priorité ; — extraire de la file l’élément le plus prioritaire ; — rendre plus prioritaire un élément déjà dans la file. Le type abstrait de cette structure de données est défini par la signature suivante : type pointer type ’a queue val val val val make_queue : int -> ’a t add_queue : ’a -> int -> ’a t -> pointer increase_priority : ’a -> pointer -> int -> ’a t -> unit extract_highest_priority_element : ’a t -> ’a Cette signature définit deux types abstraits : ’a queue pour les files à priorités contenant des éléments de type ’a et pointer qui représente un pointeur abstrait vers un élément ajouté à la structure de données (ces pointeurs seront utilisés dans les fonctions add_heap et increase_priority définies ci-dessous). La fonction make_queue permet de créer une file supportant un nombre n de niveaux de priorités, les priorités des éléments allant de 0 (plus prioritaire) à n − 1 (moins prioritaire). La fonction add_queue permet d’ajouter un élément dans la file avec une certaine priorité. À niveau de priorité égal, c’est l’élément ajouté en dernier qui est le plus prioritaire. La valeur de type pointer retournée par cette fonction doit être utilisée dans la fonction increase_priority pour changer la priorité d’un élément ajouté précédemment dans la file avec la fonction add_queue. Le changement de priorité ne sera effectif que si l’élément devient plus prioritaire (si ce n’est pas le cas ce changement n’aura aucun effet). Enfin, la fonction extract_highest_priority_elemen permet de sortir l’élément le plus prioritaire de la file. 1 Exemple. Voici une suite d’expressions qui permet de : — créer une file f à changement de priorité avec 5 priorités au plus ; — ajouter 3 éléments à f (’a’, ’b’ et ’c’) de priorité respective 4, 0 et 3 ; — extraire l’élément le plus prioritaire de f ; — changer la priorité de l’élément ’a’ à 2 ; — extraire l’élément le plus prioritaire de f. # let f = make_queue 5;; val f : ’_a queue = <abstr> # let pa = add_queue ’a’ 4 f;; val pa : pointer = <abstr> # let pb = add_queue ’b’ 0 f;; val pb : pointer = <abstr> # let pc = add_queue ’c’ 3 f;; val pc : pointer = <abstr> # extract_highest_priority_element f;; - : char = ’b’ # increase_priority ’a’ pa 2 f;; - : unit = () # extract_highest_priority_element f;; - : char = ’a’ Afin de séparer la gestion de la structure de données représentant la file à priorités du mécanisme permettant le changement de priorité, nous allons tout d’abord implémenter une structure de TAS ayant la signature : type ’a heap val make_heap : int -> ’a t val add_heap : ’a -> int -> ’a t -> unit val extract_heap : ’a t -> ’a Cette signature définit un type abstrait ’a heap pour les files à priorités. La fonction make_heap permet de créer une file vide supportant un nombre fixe n de priorités (de 0 à n − 1, où 0 est la priorité la plus forte). La fonction add_heap est utilisée pour ajouter un élément de type ’a avec une certaine priorité dans une file. Enfin, extract_heap permet d’extraire d’une file l’élément ayant la priorité la plus forte. Exercice 7 En utilisant un tableau de listes polymorphes (’a list) array pour représenter le type ’a heap, définir une implémentation de cette structure de TAS. Pour réaliser le mécanisme de changement de priorité, nous allons associer à chaque élément de la file une référence booléenne indiquant si cet élément est réellement présent dans la file. Ainsi, le changement de priorité d’un élément sera simplement réalisé par l’ajout de ce même élément (avec sa nouvelle priorité mais la même référence booléenne) dans la file, les anciennes occurences de cet élément (avec leurs anciens niveaux de priorité) étant elles toujours présentes dans la file. L’extraction de l’élément le plus prioritaire devra changer la valeur de la référence booléenne afin d’indiquer que les autres occurences de cet élément (avec des niveaux de priorités plus élevés) ne doivent plus être considérées comme appartennant à la file. Les définitions des types pointer et ’a queue sont donc les suivantes : type pointer = bool ref type ’a queue = (’a * pointer) heap Exercice 8 En utilisant les types pointer et ’a queue définis ci-dessus, écrire les fonctions de la structure de file à changement de priorité. 2