Programmation Fonctionnelle, TD4

Version & licenses
Creative Commons License

Programmation Fonctionnelle, TD4 : Listes et types algébriques.

Guyslain Naves

Exercice 1 : Ensembles par des listes

(Pour ceux qui sont en avance seulement.)

Dans cet exercice, nous cherchons à coder des ensembles mathématiques comme des listes. Chaque liste devra toujours contenir des éléments distincts deux-à-deux. On vous demande de coder les valeurs suivantes :

  1. (** l'ensemble vide *)
  2. val empty_set : 'a list

  3. (** [contains elt set] évalue si [set] contient [elt] *)
  4. val contains : 'a -> 'a list -> bool

  5. (** [union setA setB] est l'ensemble union de [setA] et [setB] *)
  6. val union : 'a list -> 'a list -> 'a list

  7. (** [intersection setA setB] est l'ensemble intersection de [setA] et [setB] *)
  8. val intersection : 'a list -> 'a list -> 'a list

  9. (** [difference setA setB] est l'ensemble des éléments de [setA] qui ne sont pas dans [setB] *)
  10. val difference : 'a list -> 'a list -> 'a list

  11. (** [symmetric_difference setA setB est l'ensemble des éléments apparaissant
  12. dans [setA] ou [setB], mais pas dans les deux à la fois *)
  13. val symmetric_difference : 'a list -> 'a list -> 'a list

  14. (** [subset setA setB] évalue si [setA] est un sous-ensemble dans [setB] *)
  15. val subset : 'a list -> 'a list -> bool

Exercice 2 : Nombres binaires sans chiffre '0'

Nous allons coder les entiers sans le chiffre '0', mais seulement avec les chiffres '1' et '2'. Ainsi, on peut montrer que tout nombre naturel $n$ se décompose en $n = \sum_{i=0}^k \alpha_i 2^i$, pour un certain choix de $\alpha_i \in \{1,2\}$.

Par exemple, $0 = \sum_{i=0}^{-1} 1 \cdot 2^{i}$, et $8 = 2 \cdot 2^0 + 1 \cdot 2^1 + 1 \cdot 2^2$, etc. Étant donné que les bits ont toujours pour valeurs des puissances de 2, on peut considérer, selon la valeur du dernier bit, qu'un entier vaut soit $1$ plus le double d'un entier, soit $2$ plus le double d'un entier, soit $0$.

  1. Proposer un type algébrique inductif pour les entiers naturels, ainsi codé. (utiliser un cas spécial pour coder l'entier $0$).
  2. Écrire une fonction succ, qui à $n$ associe $n+1$.
  3. Coder l'addition de deux entiers.

Exercice 3 : Les arbres enracinés

Nous souhaitons travailler avec des arbres d'arités arbitraires, dont les feuilles sont des entiers. Les nœuds internes ne possèdent pas d'information, sinon la liste de leurs fils.

  1. Proposer un type pour encoder les arbres enracinés.
  2. Écrire une fonction prenant deux arbres enracinés, qui les lie avec une nouvelle racine ayant pour fils ces deux arbres.
  3. Écrire une fonction prenant une liste d'entiers, et qui construit un arbre enraciné dont les feuilles sont les éléments de la liste. L'arbre ainsi construit doit avoir une hauteur de $1$.
  4. Écrire une fonction qui calcule la somme des feuilles d'un arbre enraciné.
  5. Enfin, écrire une fonction map, qui applique une fonction passée en argument à chaque feuille, et renvoie l'arbre enraciné de même forme avec les images de la fonction en feuilles.

Exercice 4 : Le type option

Le module Pervasive fournit un type bien utile, le type option permettant de coder une valeur optionnelle :

  1. type 'a option =
  2. | None
  3. | Some of 'a
  1. coder une fonction qui filtre les options d'une liste, pour garder uniquement les valeurs définies :

    1. val option_filter : 'a option list -> 'a list
  2. quel est le type de la fonction suivante ?

    1. let (>>=) e f = match e with
    2. | None -> None
    3. | Some v -> f v
  3. Utiliser >>= pour coder une fonction prenant trois arguments de type int option, et qui renvoie une option contenant la somme des trois entiers, s'ils sont définis, ou None sinon.
  4. Coder une fonction find : ('a -> bool) -> 'a list -> 'a option, qui calcule le premier élément d'une liste vérifiant un prédicat. find calcule une option car il se peut qu'aucun élément de la liste ne vérifie le prédicat.