@@ -20,7 +20,7 @@ Un noeud contiendra donc simplement une forêt.
...
@@ -20,7 +20,7 @@ Un noeud contiendra donc simplement une forêt.
>
>
> Définir quelques arbres pour pouvoir tester.
> 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 ?
> Quel est le type inféré par OCaml pour ces arbres ? Pourquoi ?
...
@@ -29,7 +29,8 @@ Un noeud contiendra donc simplement une forêt.
...
@@ -29,7 +29,8 @@ Un noeud contiendra donc simplement une forêt.
On souhaite maintenant pouvoir calculer la hauteur d'un arbre.
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.
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
### 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
...
@@ -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**.
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.
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`.
> 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).
> 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_.
...
@@ -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`.
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.
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.
**Remarque :** la fonction `min` est prédéfinie en OCaml. Son type est `'a -> 'a -> 'a`.
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`.
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
### 1.5. Reduce
...
@@ -67,15 +73,20 @@ On peut remarquer que dans le code de `minimum` et `minimum_foret`, la fonction
...
@@ -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**.
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`.
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`.
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.
> 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
## 2. FIFOs basées sur des listes
...
@@ -91,7 +102,7 @@ Une autre technique consiste à utiliser **deux** 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 :
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 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.
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.
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
...
@@ -204,11 +215,18 @@ flowchart LR
### 2.2 Type FIFO et ajout d'éléments
### 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
### 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'é
...
@@ -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.
> 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.
> 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.