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