Site WWW de Laurent Bloch
Slogan du site

ISSN 2271-3905
Cliquez ici si vous voulez visiter mon autre site, orienté vers des sujets moins techniques.

Pour recevoir (au plus une fois par semaine) les nouveautés de ce site, indiquez ici votre adresse électronique :

Programmer en OCaml avec ChatGPT
Article mis en ligne le 5 avril 2023
dernière modification le 7 avril 2023

par Laurent Bloch

Déclaration d’indépendance de l’informatique

Cette année je suis le cours de Xavier Leroy au Collège de France, consacré aux Structures de données persistantes. Ce cours me plaît parce qu’il montre que l’on peut exposer des raisonnements rigoureux sous une forme typiquement informatique, contrairement à l’idée que la rigueur d’un développement informatique ne pourrait être exposée que dans un langage mathématique. Cette déclaration d’indépendance de l’informatique me tient à cœur.

Suivre un tel cours prend tout son sens si l’on programme les exemples exposés. Le site du Collège publie les vidéos du cours et les textes de exposés, qui contiennent les programmes. Cela peut paraître puéril, mais déjà copier un programme et le faire fonctionner en apprend beaucoup, et permet ensuite de poursuivre son propre chemin.

Bien sûr, Xavier Leroy ne publie sur le site que le texte des parties de programme qui contiennent les fonctions significatives pour son propos. À charge pour l’élève de les compléter par les fonctions d’acquisition et de gestion des données et d’affichage des résultats. Ces fonctions ancillaires ne sont pas intellectuellement les plus denses, mais cela ne les empêche pas de prendre beaucoup de temps de la vie du programmeur, et de lui poser des problèmes mesquinement pratiques mais qu’il faut néanmoins résoudre. C’est le récit de mes démêlés avec ces problèmes ancillaires, et de la collaboration que j’ai entamée avec ChatGPT à cette occasion, que je vais entreprendre ici.

Débuter OCaml avec ChatGPT

Les exemples du cours de Xavier Leroy sont écrits dans le langage OCaml, dont il est un des auteurs. Je suis assez novice en OCaml, pour programmer je m’inspire essentiellement de l’excellent manuel de Pascal Manoury, Programmation de droite à gauche et vice-versa, mais parfois « ça ne compile pas ». Alors je me suis dit : « pourquoi ne pas demander à ChatGPT ? ». Aussitôt dit aussitôt fait.

Ma première question à cet oracle à la mode fut : “How do I write a OCaml program to read numbers from a file and to put them in a list ?” (ChatGPT s’était adressé à moi en anglais, je lui avais répondu de même, mais il paraît qu’il est également possible d’utiliser le français).

La réponse à cette question m’a appris que ChatGPT et moi fréquentions les mêmes auteurs, le programme proposé était très proche du mien, nous utilisions même les mêmes noms de variables, avec l’aide conjointe de l’oracle et des messages d’erreur du compilateur j’identifiai mes erreurs de syntaxe. En fait je n’avais pas compris le rôle des points-virgules, simples et doubles. Voici le résultat de nos efforts conjoints :

  1. let read_numbers filename =
  2.   let ic = open_in filename in
  3.   let rec loop acc =
  4.     try
  5.       let line = input_line ic in
  6.       let n = int_of_string line in
  7.       loop (n::acc)
  8.     with
  9.       End_of_file -> List.rev acc
  10.   in
  11.   let numbers = loop [] in
  12.   close_in ic;
  13.   print_numbers numbers;
  14.   numbers
  15. ;;

Télécharger

Ce programme répond aussi à ma seconde question : : “How do I can invoke the function print_numbers from the function read_numbers ?” (j’avais omis le point-virgule).

Les exemples de manuel donnent en général le nom de fichier sous forme d’une chaîne de caractères en dur dans le programme, c’est compréhensible parce que sinon il faut interagir avec le système d’exploitation, ce qui est toujours un peu biscornu, mais à mon avis indispensable. Voici la question : “In a OCaml function, how do I can get an argument from the command line ?”, je crois bien que là aussi ChatGPT m’a mis sur la piste :

  1. let get_filename : int list =
  2.   if Array.length Sys.argv > 1 then
  3.     let file_name = Sys.argv.(1) in
  4.     read_numbers file_name
  5.   else
  6.     []

Télécharger

Voici le fichier de test numbers.txt :

  1. 23
  2. 12
  3. 8
  4. 42
  5. 53
  6. 11
  7.  
  8. $ ./read_numbers_from_file numbers.txt
  9. 23 12 8 42 53 11

Télécharger

Bon, me voici prêt à accrocher à cet environnement utilitaire le wagon des arbres binaires de recherche du cours de Xavier Leroy. Ce ne sont pas encore des structures de données persistantes au sens du cours, mais un premier pas sur la Voie.

Programmation modulaire pour les arbres binaires de recherche

Voici un embryon de type pour les arbres binaires de recherche, emprunté au support de cours, écrit dans le fichier abr.ml :

  1. type 'a btree =
  2.   Empty
  3. | Leaf
  4. | Node of ('a btree * 'a * 'a btree)
  5.  
  6. let rec add x t =
  7.   match t with
  8.   | Empty -> Leaf
  9.   | Leaf -> Node(Leaf, x, Leaf)
  10.   | Node (a, b, c) ->
  11.      if x < b then
  12.        Node(add x a, b, c)
  13.      else if x >b then
  14.        Node(a, b, add x c)
  15.      else
  16.        t
  17. ;;
  18.  
  19. Read_numbers_from_file.get_filename

Télécharger

La notation ’a, prononcée alpha par les initiés, introduit un paramètre de type, ce qui indique que nous pourrons construire des arbres qui contiendront des valeurs de types différents (plus précisément, les valeurs contenues dans un arbre donné seront toutes de même type, mais nous pouvons créer des arbres avec à chaque fois des valeurs de types différents). Cette possibilité de définir des types d’objets qui acceptent des paramètres de type se nomme polymorphisme.

J’ai placé dans le même répertoire le fichier read_numbers_from_file.ml de la section précédente, et je vais réunir cette collection de programmes pour créer un programme exécutable. Pour ce faire, je dois compiler chaque fichier en m’arrêtant à la production du code objet, ce qui me permettra de les réunir par une édition de liens.

Production des programmes objets :

  1. ocamlc -c read_numbers_from_file.ml
  2. ocamlc -c abr.ml

Télécharger

Les programmes objets produits sont respectivement dans les fichiers read_numbers_from_file.cmo et abr.cmo. Cette compilation objet produit également deux modules nommés Abr et Read_numbers_from_file (les noms de modules commencent obligatoirement par des majuscules). L’édition de liens, qui permet aux fonctions d’un module d’appeler les fonctions déclarées dans un autre module, s’effectue de la façon suivante, en respectant l’ordre des dépendances, soit Abr dépend de Read_numbers_from_file :

  1. $ ocamlc read_numbers_from_file.cmo abr.cmo -o abr

Ça compile, ça s’exécute sans erreur, mais pour l’instant ça ne fait pas grand-chose, parce qu’il reste à introduire les données de la liste dans un arbre.

With OCaml, how can I create a binary tree of the type I have defined and put the elements of the list in the tree ?

Bon, construisons un arbre à partir d’une liste, en demandant à Pascal Manoury plutôt qu’à ChatGPT, qui là m’a déçu ; dès qu’il faudrait vraiment comprendre la question, formulée pour un être humain compétent, il n’y a plus personne (d’ailleurs si je la repose sous une forme plus simple, à la portée d’un chat ou d’un chien, ça marche) :

How can I create in OCaml a binary tree of the type I have defined and put the elements of the list in the tree ?

Mais là c’est quand même la version Manoury :

  1. let the_list = Read_numbers_from_file.get_filename in
  2.     Read_numbers_from_file.print_numbers the_list;
  3.     let the_btree = Empty in
  4.     match the_list with
  5.       [] -> the_btree
  6.     |  x::the_list -> add x the_btree

Télécharger

Bon, ça compile, la suite au prochain numéro...


Dans la même rubrique