Cours 3

Htmligure
Version & licenses
Creative Commons License

Faire des choix

Guyslain
Thursday, 21 July 2016

Retour au sommaire.

Un peu d'énumération, avec les listes.

On termine ce chapitre sur les listes en montrant comment utiliser la fonction bind, notée >>=, des listes, pour écrire simplement des algorithmes d'énumération, c'est-à-dire des algorithmes pour énumérer tous les éléments d'un ensemble.

Nous avons déjà vu que la fonction map applique une fonction à tous les éléments d'une liste. Composée avec concat, et si la fonction retourne des choix possibles associées à chaque élément, cela construit tous les choix pour tous les éléments de la liste.

Prenons un exemple. Construisons un algorithme qui choisit deux entiers, le premier entre 1 et 10 , le deuxième entre 1 et l'entier choisit en premier :

  1. open Core.Std
  2. let (>>=) = List.(>>=)

  3. let choose_two_ints =
  4. List.range ~stop:`inclusive 1 10 >>= fun first_int ->
  5. List.range ~stop:`inclusive 1 first_int >>= fun second_int ->
  6. [ (first_int, second_int) ]

Pour toutes les valeurs de 1 à 10 , cela va appeler la fonction d'argument first_int. Pour chacun, pour toutes les valeurs de 1 à first_int, cela appelle ensuite la fonction d'argument second_int. Le résultat est donc bien la liste de toutes les paires que nous voulions. Notons que nous avions construit le produit cartésien de la même façon.

Nous pouvons faire des fonctions plus compliqués, selon le même principe. Par exemple, on peut énumérer toutes les permutations d'une liste :

  1. let rec permutations list =
  2. if list = [] then [[]]
  3. else
  4. list >>= fun elt ->
  5. let remains = List.filter ~f:((<>) elt) list in
  6. permutations remains >>= fun tail ->
  7. [ elt :: tail ]


  8. let _ = permutations [1;2;3;4]
  9. - : int list list =
  10. [[1; 2; 3; 4]; [1; 2; 4; 3]; [1; 3; 2; 4]; [1; 3; 4; 2]; [1; 4; 2; 3];
  11. [1; 4; 3; 2]; [2; 1; 3; 4]; [2; 1; 4; 3]; [2; 3; 1; 4]; [2; 3; 4; 1];
  12. [2; 4; 1; 3]; [2; 4; 3; 1]; [3; 1; 2; 4]; [3; 1; 4; 2]; [3; 2; 1; 4];
  13. [3; 2; 4; 1]; [3; 4; 1; 2]; [3; 4; 2; 1]; [4; 1; 2; 3]; [4; 1; 3; 2];
  14. [4; 2; 1; 3]; [4; 2; 3; 1]; [4; 3; 1; 2]; [4; 3; 2; 1]]

Il suffit de choisir l'élément de tête, de le retirer de la liste, et de choisir une permutation des éléments restants. bind fait le travail de construire tous les choix possibles. Dans ce contexte, il faut lire une expression telle que list >>= fun elt ->comme " soit elt pris dans la liste list" .

Construisons maintenant toutes les sous-listes d'une liste : pour chaque élément, soit on le garde, soit on l'enlève. L'ordre des éléments gardés est conservé. Le principe est de procéder de droite à gauche (avec fold_right), à chaque élément, on choisit une des sous-listes du côté droit (dans subtails), ce qui permet de construire deux listes différentes selon qu'on prend ou laisse l'élément. Nous aurions aussi pu faire une fonction récursive, comme la précédente.

  1. let sublists list =
  2. let take_or_leave elt subtails =
  3. subtails >>= fun subtail -> [ subtail; elt :: subtail ]
  4. in
  5. List.fold_right list ~f:take_or_leave ~init:[[]]

  6. let _= sublists [1;2;3;4]
  7. - : int list list =
  8. [ []; [1]; [2]; [1; 2]; [3]; [1; 3]; [2; 3]; [1; 2; 3]; [4]; [1; 4]; [2; 4];
  9. [1; 2; 4]; [3; 4]; [1; 3; 4]; [2; 3; 4]; [1; 2; 3; 4]
  10. ]

Comme dernier exemple, générons toutes les listes d'entiers positifs dont la somme vaut 5 :

  1. let rec integer_partition n =
  2. if n = 0 then [[]]
  3. else
  4. List.range ~stop:`inclusive 1 n >>= fun first ->
  5. integer_partition (n - first) >>= fun others ->
  6. [ first :: others ]

  7. let _ = integer_partition 5;;
  8. - : int list list =
  9. [ [1; 1; 1; 1; 1]; [1; 1; 1; 2]; [1; 1; 2; 1]; [1; 1; 3]; [1; 2; 1; 1];
  10. [1; 2; 2]; [1; 3; 1]; [1; 4]; [2; 1; 1; 1]; [2; 1; 2]; [2; 2; 1]; [2; 3];
  11. [3; 1; 1]; [3; 2]; [4; 1]; [5]
  12. ]

De nouveau, on choisit la valeur du premier élément, on choisit le reste de la partition, et on en déduit une solution. Puisque >>= fait toutes les possibilités on obtient toutes les solutions possibles.

Retour au sommaire.