Skip to content
Snippets Groups Projects
tp5.md 5.55 KiB
Newer Older
COQUERY EMMANUEL's avatar
COQUERY EMMANUEL committed
# TP5: Parcours génériques de structure
COQUERY EMMANUEL's avatar
COQUERY EMMANUEL committed

COQUERY EMMANUEL's avatar
COQUERY EMMANUEL committed
## 1. Manipulations de listes à l'aide de fonctions génériques

On considère les fonctions suivantes prédéfinies en OCaml, voir [la documentation du module `List`](https://v2.ocaml.org/api/List.html) :
COQUERY EMMANUEL's avatar
COQUERY EMMANUEL committed

- **`List.map: ('a -> 'b) -> 'a list -> 'b list`** Cette fonction transforme une liste en utilisant la fonction passée en paramètre pour transformer les éléments un par un. Ainsi `List.map f [x1; x2; x3; ... ]` renverra une liste égale à `[f x1; f x2; f x3; ... ]`.
- **`List.filter: ('a -> bool) -> 'a list -> 'a list`** Cette fonction transforme une liste en utilisant la fonction passée en paramètre conserver uniquement certains éléments. Ainsi `List.filter f [x1; x2; x3; ... ]` renverra une liste contenant exactement les `xi` pour lesquels `f xi` vaut `true`.
COQUERY EMMANUEL's avatar
COQUERY EMMANUEL committed
- **`List.for_all: ('a -> bool) -> 'a list -> bool`** Cette fonction indique si une fonction renvoie vrai pour tous les éléments d'une liste. Ainsi `List.for_all f [x1; x2; x3; ... ]` renvoie `true` si pour tous les `xi`, on a `f xi` vaut `true`.

## 1.1. Utilisation des fonctions sur les listes

> En utilisant `List.map`, coder les fonctions suivantes :
>
> - Une fonction `f1` qui prend une liste d'`int` et renvoie la liste de leur représentation sous forme de `string`.
> - Une fonction `f2` qui prend un `int` `x` et une liste d'`int` `l` et renvoie la liste transformée en multipliant chaque élément de `l` par `x`.
> - Une fonction `f3` qui prend deux `int` `x` et `y` et une liste d'`int` `l` et renvoie la liste (de `bool`) indiquant pour chacun des éléments de `l` s'il est bien compris entre `x` et `y`.
COQUERY EMMANUEL's avatar
COQUERY EMMANUEL committed

Bien tester vos fonctions avec `assert`.

> En utilisant `List.filter`, coder les fonctions suivantes :
>
> - Une fonction `f4` qui prend deux `int` `x` et `y` et une liste d'`int` `l` et renvoie la liste des éléments de `l` qui sont compris entre `x` et `y`.
> - Une fonction `f5` qui prend une liste de liste d'`int` et renvoie la liste sans les (sous-)listes vides.
COQUERY EMMANUEL's avatar
COQUERY EMMANUEL committed

Bien tester vos fonctions avec `assert`.

En OCaml, on peut voir un opérateur comme une fonction en le plaçant tout seul entre parenthèses. Ainsi `(!=)` est une fonction qui prend deux arguments et renvoie `true` s'ils sont différents. Ainsi `(!=) 1 2` renvoie `true`, alors que `(!=) 1 1` renvoie `false`.
> Recoder la fonction `f5` sans le mot clé `fun` en utilisant une application partielle de `(!=)`.
COQUERY EMMANUEL's avatar
COQUERY EMMANUEL committed

On peut bien sûr combiner `List.map` et `List.filter`.

> Coder une fonction `f6` qui prend une liste d'`int option` `l` et renvoie une liste d'`int` contenant les valeurs `int` contenues dans `l`. Par exemple, `f6 [ Some 3; None; Some 18; Some 42; None; Some 37; None]` vaudra `[3; 18; 42; 37]`.
COQUERY EMMANUEL's avatar
COQUERY EMMANUEL committed

## 1.2 Recodage de fonctions sur les listes

> Recoder `List.map`, `List.filter` et `List.for_all`.

**Faire valider votre progression par votre chargé de TP**
COQUERY EMMANUEL's avatar
COQUERY EMMANUEL committed

## 2. Arbre n-aires: recodage
COQUERY EMMANUEL's avatar
COQUERY EMMANUEL committed

Dans cet exercice, on reprend les fonctionnalités développées dans la section 1. du [TP4](tp4.md), mais en les recodant avec les fonctions déjà fournies avec OCaml.

Remarque : en OCaml, on peut écrire `fun x y -> ...` à la place de `fun x -> fun y -> ...`.
COQUERY EMMANUEL's avatar
COQUERY EMMANUEL committed

COQUERY EMMANUEL's avatar
COQUERY EMMANUEL committed
### 2.1. Recodage de quelques fonctions de base avec la bibliothèque standard OCaml
COQUERY EMMANUEL's avatar
COQUERY EMMANUEL committed

> Reprendre le type `'a arbre_n` du TP4, section 1.1

On pourra reprendre les tests écrits lors du TP4.

> Recoder la fonction `hauteur_arbre` sans utiliser `hauteur_foret`, mais en appelant directement `List.map` et `List.fold_left` pour extraire les hauteurs des arbres fils et trouver la hauteur maximale parmi celles-ci.

> Recoder `list_of_arbre_aux` en utilisant `List.fold_right` pour remplacer les appels à `list_of_foret`.
> Encapsuler `list_of_arbre_aux` avec un `let ... in ...` dans la définition de `list_of_arbre`.
COQUERY EMMANUEL's avatar
COQUERY EMMANUEL committed
> On écrira le `let` avant de prendre l'argument de `list_of_arbre`.
COQUERY EMMANUEL's avatar
COQUERY EMMANUEL committed

**Faire valider votre progression par votre chargé de TP**

COQUERY EMMANUEL's avatar
COQUERY EMMANUEL committed
### 2.2. Gestion d'option, fold et minimum
COQUERY EMMANUEL's avatar
COQUERY EMMANUEL committed

Pour gérer proprement le calcul du minimum, on va s'équiper d'un décorateur `lift_option_2` ayant le comportement suivant. Soit `f: 'a -> 'a -> 'a`. On suppose que `g = lift_option_2 f`. Alors `g` aura le type `'a option -> 'a -> 'a option`. Si le premier argument de `g` est `None`, alors `g` renvoie `Some x` si `x` est son second argument. Sinon `g` renvoie `Some (f y x)``y` est la valeur contenue dans son premier argument et `x` est son second argument.

> Définir `lift_option_2` en commençant par préciser son type. Tester avec `assert` en passant la fonction `min` à `lift_option_2`.

On veut à présent définir `fold_left_arbre` qui agrège une valeur via un accumulateur à la manière de `List.fold_left`, mais en parcourant un arbre et pas une liste.
COQUERY EMMANUEL's avatar
COQUERY EMMANUEL committed

> Définir le type, puis coder `fold_left_arbre`. On pourra utiliser intelligemment `List.fold_left` pour gérer le cas des `Noeud`.
COQUERY EMMANUEL's avatar
COQUERY EMMANUEL committed
> Tester en calculant la somme des éléments d'arbres bien choisis.

On peut remarquer que `reduce` du TP4 ressemble énormément à `fold_left_arbre`: les deux vont parcourir les éléments de l'arbre les combinant via un accumulateur. Elles diffèrent cependant sur les points suivants:

- `reduce` prend en argument une fonction de type `'a -> 'a -> 'a` alors que `fold_left_arbre` prend une fonction un peu plus générique de type `'b -> 'a -> 'b`.
- `reduce` renvoie forcément une `option` alors que `fold_left_arbre` renvoie uniquement une option si `'b` est lui-même une `option`.

> En utilisant intelligemment `fold_left_arbre`, recoder `reduce`.
COQUERY EMMANUEL's avatar
COQUERY EMMANUEL committed

> Recoder `list_of_arbre` en utilisant `fold_left_arbre`.

**Faire valider votre progression par votre chargé de TP**