diff --git a/tp/tp4.md b/tp/tp4.md index 1bcb105371447aadbd257b3abf7a94432a03ce71..cfe00063d5fc251f87d9efaf36309971a1334939 100644 --- a/tp/tp4.md +++ b/tp/tp4.md @@ -20,7 +20,7 @@ Un noeud contiendra donc simplement une forêt. > > Définir quelques arbres pour pouvoir tester. > -> Donner deux exemples d'arbres ne contenant **aucun** éléments. +> Donner deux exemples d'arbres ne contenant **aucun** élément. > > Quel est le type inféré par OCaml pour ces arbres ? Pourquoi ? @@ -29,7 +29,8 @@ Un noeud contiendra donc simplement une forêt. On souhaite maintenant pouvoir calculer la hauteur d'un arbre. Comme un arbre peut contenir une forêt, il faut deux fonctions mutuellement récursives: une fonction qui donne la hauteur d'un arbre et une autre qui donne la hauteur maximale des arbres dans une forêt. -> Coder `hauteur_arbre` et `hauteur_foret`, deux fonctions mutuellement récursives qui calculent respectivement la hauteur d'un arbre et la hauteur maximale des arbres d'une forêt. Tester avec `assert`. +> Coder `hauteur_arbre` et `hauteur_foret`, deux fonctions mutuellement récursives qui calculent respectivement la hauteur d'un arbre et la hauteur maximale des arbres d'une forêt. +> Tester avec `assert`. ### 1.3. Éléments d'un arbre @@ -42,11 +43,13 @@ Comme un arbre peut contenir une forêt, il faut **deux fonctions mutuellement r Par ailleurs on veut éviter de faire des concaténations qui vont s'avérer coûteuses, on va donc écrire ces fonctions en **s'appuyant sur un accumulateur**. Les fonctions vont ainsi ajouter les éléments de l'arbre/de la forêt à l'accumulateur. -> Coder deux fonctions mutuellement récursives `list_of_arbre_aux` et `list_of_foret` qui vont prendre un arbre / une forêt en argument, ainsi qu'une liste d'éléments `acc` qui vont ajouter en tête de `acc` les éléments de l'arbre / de la forêt. Vous pouvez aussi commencer par écrire une version **sans** accumulateur et la modifier ensuite. +> Coder deux fonctions mutuellement récursives `list_of_arbre_aux` et `list_of_foret` qui vont prendre un arbre / une forêt en argument, ainsi qu'une liste d'éléments `acc` qui vont ajouter en tête de `acc` les éléments de l'arbre / de la forêt. +> Vous pouvez aussi commencer par écrire une version **sans** accumulateur et la modifier ensuite. > > Tester avec `assert`. > -> Placer la définition des deux fonctions à l'intérieur d'une fonction `list_of_arbre` (via un `let ... in ...`). Le code de `list_of_arbre` fera ensuite simplement appel à `list_of_arbre_aux` avec un accumulateur initial vide. +> Placer la définition des deux fonctions à l'intérieur d'une fonction `list_of_arbre` (via un `let ... in ...`). +> Le code de `list_of_arbre` fera ensuite simplement appel à `list_of_arbre_aux` avec un accumulateur initial vide. > > Modifier les tests précédents pour tester `list_of_arbre` et pas `list_of_arbre_aux` (qui est maintenant masquée). @@ -56,10 +59,13 @@ On veut maintenant extraire _l'élément minimal d'un arbre_. Attention, si l'arbre est vide, le minimal n'est **pas** défini, le résultat sera donc un `'a option`. Il faudra prendre en compte cette spécificité lors du traitement des appels récursifs, typiquement en faisant un pattern matching sur le résultat de l'appel récursif. -Remarque : la fonction `min` est prédéfinie en OCaml. Son type est `'a -> 'a -> 'a`. On l'utilisera pour obtenir le minimum de deux éléments de l'arbre. -On évitera cependant de l'utiliser directement avec des `option` car elle ne donnera pas le résultat voulu. Par exemple, `min None (Some 3)` vaut `None`. +**Remarque :** la fonction `min` est prédéfinie en OCaml. Son type est `'a -> 'a -> 'a`. +On l'utilisera pour obtenir le minimum de deux éléments de l'arbre. +On évitera cependant de l'utiliser directement avec des `option` car elle ne donnera pas le résultat voulu. +Par exemple, `min None (Some 3)` vaut `None`. -> Définir deux fonctions mutuellement récursives `minimum` et `minimum_foret` qui donne le minimum d'un arbre / d'une forêt. Tester avec `assert`. +> Définir deux fonctions mutuellement récursives `minimum` et `minimum_foret` qui donne le minimum d'un arbre / d'une forêt. +> Tester avec `assert`. ### 1.5. Reduce @@ -67,15 +73,20 @@ On peut remarquer que dans le code de `minimum` et `minimum_foret`, la fonction On pourrait donc généraliser ce code pour qu'il fonctionne avec **n'importe quelle fonction de combinaison des résultats**. La fonction généralisée est souvent appelée `reduce`. -On veut donc coder les fonctions `reduce` et `reduce_foret` qui généralisent `minimum`. Elles prendront un argument supplémentaire `f` qui est la fonction de combinaison des résultats. Dans le code de ces fonctions, `f` sera utilisée à la place de `min`. Si l'arbre / la forêt contient des éléments de type `'a`, alors le type de `f` sera `'a -> 'a -> 'a`. +On veut donc coder les fonctions `reduce` et `reduce_foret` qui généralisent `minimum`. +Elles prendront un argument supplémentaire `f` qui est la fonction de combinaison des résultats. +Dans le code de ces fonctions, `f` sera utilisée à la place de `min`. +Si l'arbre / la forêt contient des éléments de type `'a`, alors le type de `f` sera `'a -> 'a -> 'a`. -> Coder `reduce` et `reduce_foret`. Tester en reprenant les cas de test utilisés pour `minimum`, en utilisant `min` comme valeur pour `f`. +> Coder `reduce` et `reduce_foret`. +> Tester en reprenant les cas de test utilisés pour `minimum`, en utilisant `min` comme valeur pour `f`. Si ce n'est pas déjà fait, définir quelques exemples arbres dont le contenu sera de type `int`. > Tester `reduce` et `reduce_foret` avec un fonction qui fait l'addition (en `int`) de ses deux arguments, ou le produit des éléments, le maximum etc. -**Remarque** : le type de l'addition est `int -> int -> int`. Cela fonctionne car le type de `reduce` est `('a -> 'a -> 'a) -> 'a arbre_n -> 'a option`, donc `reduce` a aussi le type `(int -> int -> int) -> int arbre_n -> int option`. +**Remarque** : le type de l'addition est `int -> int -> int`. +Cela fonctionne car le type de `reduce` est `('a -> 'a -> 'a) -> 'a arbre_n -> 'a option`, donc `reduce` a aussi le type `(int -> int -> int) -> int arbre_n -> int option`. ## 2. FIFOs basées sur des listes @@ -91,7 +102,7 @@ Une autre technique consiste à utiliser **deux** listes. La première (à gauche) est destinée à recevoir les nouveau éléments, alors que la seconde à droite sera utilisée pour stocker les éléments à retirer : - dans la liste de gauche, les éléments sont stockés dans l'ordre **inverse** de leur insertion : le dernier élément inséré est en tête de liste. -- dans la liste de droite, les éléments sont stocké dans l'ordre où ils doivent être récupérés, c'est à dire **le plus ancien en tête de liste**. +- dans la liste de droite, les éléments sont stocké dans l'ordre où ils doivent être récupérés, c'est-à -dire **le plus ancien en tête de liste**. Reste à transférer des éléments entre la liste de gauche et celle de droite. C'est là que cette technique trouve son efficacité : on transfère de la gauche à la droite lorsque l'on essaie de retirer un élément de la liste de droite alors qu'elle est vide. @@ -204,11 +215,18 @@ flowchart LR ### 2.2 Type FIFO et ajout d'éléments -> Définir un type `'a fifo` avec un seul constructeur contenant deux listes dont les éléments sont de type `'a`. Définir quelques exemples d'éléments de ce type. +> Définir un type `'a fifo` avec un seul constructeur contenant deux listes dont les éléments sont de type `'a`. +> Définir quelques exemples d'éléments de ce type. + +<!-- pour séparer les citations --> -> Définir une fonction `push_fifo` qui prend en argument un élément `e` et une fifo `f` et renvoie la fifo contenant les éléments de `f` puis `e` en insérant `e` en tête de la liste de gauche. Tester avec `assert` et les fifos exemples créées précédement. +> Définir une fonction `push_fifo` qui prend en argument un élément `e` et une fifo `f` et renvoie la fifo contenant les éléments de `f` puis `e` en insérant `e` en tête de la liste de gauche. +> Tester avec `assert` et les fifos exemples créées précédement. -> Définir une fonction `push_list_fifo` qui prend une liste d'éléments `l` et une fifo `f` et renvoie la fifo contenant tous les éléments de `f` suivis de tous les éléments de `l` insérés dans l'ordre de `l` (i.e. l'élément en tête de `l` avant les autres). Tester avec `assert` et les fifos exemples créées précédement. +<!-- pour séparer les citations --> + +> Définir une fonction `push_list_fifo` qui prend une liste d'éléments `l` et une fifo `f` et renvoie la fifo contenant tous les éléments de `f` suivis de tous les éléments de `l` insérés dans l'ordre de `l` (i.e. l'élément en tête de `l` avant les autres). +> Tester avec `assert` et les fifos exemples créées précédement. ### 2.3 Récupération des éléments et transfert @@ -224,4 +242,6 @@ Le résultat de `pop_fifo` sera une paire contenant d'une part la fifo sans l'é > Coder la fonction `pop_fifo` et la tester avec `assert` et les fifos exemples créées précédement. +<!-- Séparateur de citation --> + > Coder la fonction `pop_all_fifo` qui prend une fifo `f` et renvoie la liste contenant tous les éléments dans l'ordre de `f`, c'est à dire qu'on veut le premier élément retiré de `f` en tête de la liste résultat. Tester avec `assert` et les fifos exemples créées précédement.