[Atom] [Talk Atom]    [Git] [Mail] [Reload]
Liens : mdown · hacks · divers · cabale · à propos +

En bref aussi

Les temps sont durs, et le temps nous manque…
Mais nous sommes toujours là ! bluestorm et moi. —rz0

Comme rz0 l’a admirablement fait remarquer, le blog est plutôt mort ces temps-ci. Sans surprises, je suis occupé depuis le début de l’année, et le temps pour poster des billets en a diminué d’autant. Je me suis fixé l’objectif de ne pas passer plus d’une heure à écrire ce billet (écriture seulement, il y aura sans doute de la relecture ensuite), et ça me paraît un pari assez raisonnable, bien que nettement plus ambitieux que les billets précédents. La qualité en souffrira certainement, mais j’essaie de trouver un équilibre.

Je remarque d’ailleurs que je ne suis pas le seul à être occupé : tous ces gens qui avaient promis juré que oui, ils feraient des efforts pour poster des commentaires de temps en temps, histoire qu’on conserve la motivation, ils ont visiblement un travail fou. Tant pis ; de toute façon je n’ai pas les moyens (temps, motivation et envie) d’écrire de gros billets bien préparés en ce moment. Si j’écris celui-ci, c’est parce que j’ai honte de laisser cet espace tellement vide alors que rz0 a fait tant d’effort pour m’installer un petit coin bien douillet. Et j’espère aussi que ce que j’ai à vous raconter pourrait vous intéresser.

Débuts en Coq

Cette année, j’ai décidé de me lancer dans le vaste monde des assistants de preuve. En un mot, ce sont des programmes qui permettent d’écrire des preuves mathématiques, et qui les valident : ils savent dire si oui ou non, une preuve est correcte.

Je leur vois deux intérêts principaux. D’une part, ils permettent de se redonner confiance en mathématiques ; si vous connaissez le malaise de celui qui écrit un brouillon de preuve, mais sans savoir vraiment si elle est juste ou contient une erreur désagréable que vous n’aviez pas vue, vous comprendrez ce que je veux dire. Plus généralement, c’est un peu comme la différence, en informatique, entre écrire du pseudo-code, et écrire dans un vrai langage de programmation : l’avantage d’un vrai langage, c’est que vous pouvez exécuter le programme pour vérifier qu’il fonctionne (et en particulier vérifier sa syntaxe, etc. automatiquement), alors qu’on est rarement motivé pour relire avec soin un pseudo-code. L’ordinateur apporte un retour d’expérience (feedback) direct, impartial et incontestable.

D’autre part, les assistants de preuve sont essentiellement des langages de programmation. Ils se placent en effet à cheval entre la théorie des types (côté informatique) et la théorie de la démonstration (côté mathématiques) : c’est essentiellement le même domaine, vu de points de vue différents. On parle souvent de l’isomorphisme de Curry-Howard, mais ce théorème précis concerne des systèmes bien précis, et l’étendue de la correspondance est en fait beaucoup plus large ; fondamentalement, depuis le début du 20e siècle, on pense les preuves formelles comme des programmes (fonctionnels). Ces outils font donc de bons mélanges entre des preuves très formelles et des langages très fortement typés, et ça a tout pour me plaire. On peut d’ailleurs aussi utiliser ces systèmes pour prouver des choses sur les langages de programmation (tous paradigmes confondus, cette fois-ci).

Il existe plusieurs systèmes d’assistants à la démonstration. Les plus utilisés actuellement sont Coq et Isabelle (et éventuellement Twelf et HOL-Light, avec aussi des anciens couverts de lauriers (Mizar), et de jeunes qui explorent l’espace de recherche (Agda)). Ces systèmes ont des qualités et des défauts variés. J’utilise Coq. D’une part parce que c’est le système conçu en France, et donc je suis entouré de gens qui l’utilisent, l’enseignent, voire le développent.α D’autre part, j’utilise pour apprendre les bases le livre en ligne Certified Programming with Dependent Types, qui conseille d’utiliser Coq et qui a certainement ses raisons, moi, je ne connais pas assez le domaine pour faire un choix informé.

Ces outils sont majoritairement codés dans un des langages dont le nom contient « ML » et ne commence pas par « X ». C’est une corrélation historique, puisque le langage ML (notre grand-père à tous) a été créé conjointement à l’assistant de preuve LCF.

α : J’ai passé un été à faire de l’OCaml dans le même bureau qu’un des développeurs actuels de Coq. On se sent bien encadré.

β : Encore par patriotisme : son auteur, Adam Chlipala, est un citoyen émérite du canal irc #ocaml.

Au passage, si vous envisagez vous-même de vous intéresser un jour au sujet, je suis assez content de ce bouquin. En particulier, il prend surtout ses exemples dans le monde des langages de programmation : dès le premier chapitre, on compile des expressions arithmétiques simples vers une machine à pile simple, en rajoutant du typage à gogo, et sera donc plus accessible qu’un livre orienté vers la logique formelle si vous vous sentez plutôt informaticien. Une connaissance (au moins des bases) de la programmation fonctionnelle est tout de même indispensable.

Il est temps de signaler les deux articles qu’asmanur a écrit comme une petite introduction à Coq (un passe-temps qu’il a certainement abandonné assez vite, comme tous les autres) : Voyage au bout de la logique, et sa deuxième partie. Si vous vous intéressez à la discussion sur le choix de l’assistant à la démonstration, vous pouvez aussi lire l’introduction du livre de Chiplala. Au passage, le mode Emacs qu’il recommande, Proof General, est vraiment très bien.

Programmation par contraintes

Cette fois-ci, cela tient plus de l’anecdote, mais je trouve ça assez amusant pour avoir envie de vous en parler. En plus de la logique formelle fonctionnelle typée et des hautes sphères éthérées de la théorie des catégories, je fais cette année des choses bassement matérielles qui demandent de la programmation. Évidemment, je fais tout en OCaml.

Depuis cet été, je suis assez séduit par les types fantômes. C’est un outil vraiment puissant et agréable, à tel point que je suis tenté d’en mettre un peu partout dans mes divers projets. Par exemple, je dois coder un projet de bataille navale en réseau (et d’ailleurs c’est assez ennuyeux ; je prends sur mon temps de développement pour vous écrire cet article). Ça a l’air assez trivial, mais j’ai perdu tellement de temps à refactoriser dans tous les sens pour avoir le typage le plus expressif possible que j’en suis venu à m’auto-imposer la règle suivante : « Interdiction d’utiliser les types fantômes ! »

Et vous, avez-vous des règles personnelles que vous appliquez avec cruauté, pour éviter de perdre votre temps dans des considérations, certes intéressantes, mais déraisonnables pour le projet précis sur lequel vous travaillez ?

J’en profite pour vous signaler que j’étais passé à côté jusqu’à présent, mais j’ai découvert récemment que la bibliothèque standard OCaml utilise elle aussi, des types fantômes, ma bonne dame : ça se passe dans le module le plus haut niveau de la bibliothèque, Bigarray.

Traitement d’images

Je suis, par un curieux hasard de circonstances, un cours de traitement d’images. C’est un sujet très éloigné de mes centres d’intérêt habituels, mais je ne le regrette pas. Je vois défiler beaucoup de jolies photos, et de méthodes pour les améliorer encore, parfois franchement inventives. J’ai un professeur formidable, qui est un mordu de la photographie, mais aussi un amateur de l’analyse de Fourier. Sans entrer dans les détails pénibles, il nous fait des démonstrations « avec les mains » qui sont parfois assez sympathiques, et donnent un petit coup de jeune à toutes ces choses qui sombrent lentement dans l’oubli quand on ne les utilise pas.

Au cas où ça vous intéresse, voici un exemple d’algorithme que nous avons étudié : Colorization Using Optimization. Il s’agit de donner des couleurs à des images en noir et blanc, à partir de quelques indications de l’utilisateur (des traits de couleur connue). L’idée de base, c’est de supposer que deux pixels de luminosité proche doivent être de couleur proche. On peut alors exprimer la teinte de chaque pixel en fonction de celle de ses voisins et, combiné aux conditions initiales de l’utilisateur, ça donne un gros système linéaire (une grosse matrice) qu’on fournit à une fonction de résolution et pouf, une image en couleur. Ça marche étonnamment bien.

Pour ce cours, j’ai participé à l’écriture de bindings OCaml vers des bibliothèques C (ou interfacées par l’intermédiaire du C), par exemple OpenCV ou SuiteSparse. C’est très drôle, on retrouve la joie du segfault (et c’est encore mieux à plusieurs). Je ne m’étais jamais vraiment plongé dans l’interface C-OCaml, et je peux vous dire que ce n’est pas inoubliable mais ça reste une expérience amusante. Cela m’a d’ailleurs permis de mettre mon petit grain de sel dans un tutoriel de Cacophrène à ce sujet sur le SdZ. Ça fait toujours une introduction en français à ce sujet, qui peut servir de mise en bouche, mais si un jour vous voulez vraiment coder quelque chose je vous conseille ensuite de lire conjointement le manuel officiel pour les idées, et le tutorial en anglais de François Monnier pour les exemples de code. Attention au DA-Ocaml, sur ce point il est un peu vieux.

Une petite réaction pour finir ?

Que serait mon billet mensuel sans une référence, ou du moins une allusion, à un petit papier à se mettre sous la dent ? J’en ai survolé une bonne poignée depuis la rentrée, mais les derniers que j’ai croisés sont des articles de Gilad Bracha. C’est un type qui a commencé ses exploits en codant un système Smalltalk avec annotations optionnelles de typage très performantγ, pour aller ensuite réutiliser ses compétences en travaillant sur Java, sa spécification et sa VM chez Sun pendant quelques temps, avant de repartir construire un nouveau langage dynamique, Newspeak.

γ : Il a travaillé avec les gens de Self, qui ont inventé le concept de JIT et toutes les optimisations méchantes de langage dynamique

J’ai jeté un coup d’oeil à la bête. Comme vous imaginez, les langages très dynamiques ne sont pas forcément ceux qui me tentent le plus, mais ça fait du bien de voir ce qui se fait ailleurs de temps en temps. J’ai aussi lu deux de ses papiers au hasard : Executable Grammars in Newspeak, et Pluggable Type Systems.

Le premier papier présente une façon possible de créer une bibliothèque de parsing combinators dans un langage dynamique. Comme l’annonce l’auteur d’entrée de jeu, c’est plutôt le point fort des langages fonctionnels (l’étalon dans le domaine étant le très bon Parsec de Haskell). Il promet que les fonctionnalités nouvelles de son langage, ainsi que son fort dynamisme, permettront d’en faire une traduction « objet dynamique » adaptée. Je n’ai pas été émerveillé par le résultat (en particulier, comme toutes les approches « DSL internes au langage », la syntaxe n’est au final pas si géniale que ça), mais ça reste une lecture intéressante. Il discute aussi de la facilité ou non à typer ces opérations dans un langage statique, mais le référentiel semblant être celui de Java, on en apprend plus sur l’état des systèmes de types mainstream que sur le fond du problème.

Le deuxième article n’est pas vraiment un article scientifique, mais plutôt une prise de position de l’auteur. Il voudrait qu’on envisage les systèmes de type non pas comme une donnée fondamentale du langage de programmation, à laquelle tout programme dans ce langage doit se soumettre, mais comme une étape supplémentaire, optionnelle. C’est une idée très séduisante, mais assez délicate à mettre en place en pratique (la plupart des avantages théoriques des systèmes de types actuels venant justement de leur capacité à (presque) tout contrôler).

Il voudrait aussi que l’inférence soit optionnelle/désactivable, en un mot « pluggable », ce qui est un point de vue intéressant (et trouve des échos chez les théoriciensδ). Il voudrait même pouvoir faire cohabiter plusieurs systèmes d’inférence pour « choisir le meilleur selon les situations », et là je ne suis franchement pas convaincu : ça mène à une situation où le type repose sur beaucoup d’heuristiques diverses que le programmeur ne maîtrise pas en général, et cela pourrait à mon avis poser plus de problèmes que ça n’en résoud. Ça reste une lecture intéressante, c’est agréable de voir que les universitaires grisonnants ne sont pas les seuls à se poser la question.

Pour amadouer mes lecteurs potentiels les plus revêches, je dois signaler que cet article cite explicitement les essais d’ajout (partiel) d’un typage statique au langage Erlang.

δ : Pour les systèmes de type « partiels » ou désactivables, on pourra regarder par exemple du côté du Blame Calculus de Wadler.

P.S. : Mon pari de temps n’a pas été tenu, j’ai plutôt mis une heure et demie, mais c’est toujours agréable d’écrire. Ma bataille navale avance assez bien : les clients peuvent se connecter, lancer des parties et placer leurs bateaux, et je vais bientôt être obligé de coder la partie où ils tirent les uns sur les autres. Heureusement, j’ai glissé des variantes polymorphes pour que le type des fonctions reflète le protocole de communication.

[ tag:blog.huoc.org,2009:bluestorm/7 ]
Gabriel Scherer (bluestorm).
Le 27.11 2009 à 03:09.

[>] Commentaires[Atom]

# gnomnain
27.11.09, 19:34.

Ouais ! Un billet ! J'ai pas grand chose à dire (à part que non, les commentateurs ne sont pas en grève), mais il y a pas mal de liens intéressants.
Sinon, je ne m'applique pas encore de contraintes comme "pas de types fantômes" quand je code, mais je pense que je devrais si je voulais terminer un projet un jour :-°
[ tag:blog.huoc.org,2009-11-27:1259346899.20233 ]

# rushou
29.11.09, 11:54.

Coucou,
J'aime ce billet où on découvre plein de liens intéressant avec un petit retour qui va bien dessus, merci :) .
Je pensais que la partie sur la programmation par contraintes allait causer du paradigme et non de contraintes sur le développement (et je ne code pas assez pour me contraindre...). C'est amusant de voir que se servir des "trucs bien" peut ralentir un projet à ce point.
En tout cas je songeais justement à me trouver une référence pour coq, là j'ai trouvé !
[ tag:blog.huoc.org,2009-11-29:1259492074.29963 ]

# SpiceGuid
29.11.09, 17:00.

Le code de l'arbre rouge-noir de Certified Programming with Dependent Types me paraît sous-spécifié. Je ne vois pas de code qui garantisse que l'arbre rouge-noir est bien un arbre ordonné. Autrement c'est sans doute une excellente introduction qui démine assez bien le terrain pour le bon programmeur ML qui voudra bien sacrifier un temps non négligeable pour Coq.
Mon expérience personnelle c'est qu'il s'agit essentiellement d'un système fait par des théoriciens des types pour des logiciens.
• du fait que les types dépendants sont suffisamment expressifs pour que les enregistrements soient encore plus puissants que le système de module, la librairie standard ne propose aucune hiérarchie de modules ou de types-classes pour des notions aussi élémentaires que setoid / monoid / group   
• la bibliothèque standard, le langage de tactique, les types dépendants, l'approche par la logique, le large choix des moyens d'implantation, tout contribue à rendre le développement plus laborieux et plus fragile que prévu
• au final c'est sans doute trop de distractions pour le mathématicien qui s'intéresse avant tout à la chose mathématique
• l'extraction de programme souffre d'un problème de performance (sans doute lié aux problèmes de fondements identifiés par Alain Prouté) qui amoindrit l'utilité pour le programmeur ML

Des types fantômes il y en a aussi dans LablGtk. Les types fantômes sont en concurrence avec l'approche POO où il suffit d'étendre le type de base avec les capacités voulues.
[ tag:blog.huoc.org,2009-11-29:1259510406.5905 ]

# robocop
29.11.09, 19:22.

Merci de nous faire part de toutes tes expériences du moment, c'est très interessant, même si je ne comprend pas tout. 
Il y a quelque chose qui ressort quand même pas mal dans nombre de tes articles, c'est l'importance que tu attaches aux types. J'ai la facheuse impression d'être passé à coté de quelque chose de fondamentale, pour moi, les types ce n'est qu'une vérification supplémentaire qui est fait à la compilation et ou à l'interpretation, mais à la façon dont tu en parles, le système de type semble le coeur même d'un langage de programmation.

Si comme je le pressent, je loupe vraiment quelque chose, pourrais-tu disserter rapidement la-dessus ?

Merci :).
[ tag:blog.huoc.org,2009-11-29:1259518953.5905 ]

# The_third_man
30.11.09, 00:34.

Très sympa cet article. Le Coq à l'air marrant, faudrait voir ce qu'on peut faire avec du coté apprentissage (par exemple, retrouver une formule mathématique préexistante).
[ tag:blog.huoc.org,2009-11-30:1259537696.7271 ]

# bluestorm
30.11.09, 22:37.

Spiceguid : je ne vois pas exactement comment remplacer les types fantômes de BigArray par des objets. Quand il s’agit de mettre des permissions sur le type (lecture/écriture par exemple), je vois assez bien comment représenter cela avec des objets, mais dans ce cas il s’agit plutôt de pouvoir typer fiablement des fonctions d’extractions : tu as quelque chose comme (en simplifié, cf. la doc pour les types exacts) type 'a bigarray, où 'a est un type Caml qui n’est pas utilisé concrètement (bigarray utilise des représentations plus bas niveau, à la taille fixée), mais qui sert à bien typer les fonctions de lecture/écriture, comme un tableau classique :
val get : 'a bigarray -> int -> 'a
val set : 'a bigarray -> int -> 'a -> unit

Je ne suis pas sûr qu’un objet soit satisfaisant ici, étant donné que l’intérêt principal n’est pas une forme de sous-typage, mais la présence d’un composant de type qui nous intéresse.

Pour ce qui est de Coq, je suis conscient que c’est un système qui a ses défauts, en particulier en matière d’ingénérie logicielle, mais je pense qu’il reste important d’acquérir des compétences en assistants de preuve. Je connais ton avis (ta rancoeur ?) sur l’utilisabilité pour le grand public de ces outils avancés, mais je pense qu’il reste préférable que le plus de gens possibles s’y intéressent, ne serait-ce que pour donner naissance dans le futur à une nouvelle génération d’outils plus accessibles.

robocop > effectivement je pense que le système de typage expose des choses fondamentales (qu’on ne voit pas toujours, mais qui sont toujours présentes, et qu’il est donc intéressant d’expliciter au maximum, ne serait-ce que pour savoir précisément ce que c’est). J’écrirai peut-être un billet là dessus à l’occasion, mais comme ça je ne saurais pas exactement expliquer l’idée de fond. Tu as quelques idées (à un stade encore infantile) dans mon article sur le typage sur le SdZ, mais ça n’aborde aucun système avancé.

The_third_man > qu’entends-tu pas "apprentissage" ? Si tu parles de la démonstration automatique (tu donnes un énoncé et pouf, il trouve une preuve), c’est un champ de recherche mais qui est légèrement différent du rôle de code (aider les gens à écrire leurs preuves). Globalement, c’est un problème difficile et qui se heurte à un problème de fond : les ordinateurs ne savent pas vraiment ce qui est "intéressant" en mathématique (en tout cas pour l’instant, mais o n sent bien que c’est une notion tres très délicate), et ne peuvent donc pas vraiment générer d’idées nouvelles comme le ferait un mathématicien. Bien sûr, il peut aider à rédiger les preuves, et pour cela Coq intègre des mécanismes d’automatisation des parties évidentes des preuves, mais il n’est pas pensé pour faire tout le travail à ta place.

[ tag:blog.huoc.org,2009-11-30:1259617024.9742 ]

# Cacophrene
07.12.09, 13:40.

Toujours agréable à lire ! Je ne commente pas souvent mais j'apprécie les thèmes variés qui sont abordés ici, avec plusieurs niveaux de lecture possibles. C'est rare les billets qui contiennent juste ce qu'il faut pour le lecteur lambda et suffisamment de liens pour qui veut approfondir un sujet.

Pour l'approche objet vs les types fantômes, je crois qu'on pourrait concevoir une classe bigarray_skel avec les propriétés de base, et l'utiliser pour dériver des classes pour toutes les spécialisations. C'est effectivement comme ça qu'est construit LablGTK, mais ce qui se justifie pour une lib qui définit des widgets avec une hiérarchie assez poussée ne l'est peut-être pas autant pour la manipulation de tableaux. Par contre il est clair que cette vision serait en rupture nette avec le reste de la lib standard d'OCaml, en tout cas sous sa forme actuelle.

Ces menues considérations font rêver d'un système de typage à base de contraintes qui utiliserait des types généraux pour offrir plus de nuances que la dichotomie polymorphe/pas polymorphe (par ex. en définissant des groupes de types qui partagent certaines propriétés).
[ tag:blog.huoc.org,2009-12-07:1260189633.2708 ]

# bluestorm
08.12.09, 18:30.

Ces menues considérations font rêver d’un système de typage à base de contraintes qui utiliserait des types généraux pour offrir plus de nuances que la dichotomie polymorphe/pas polymorphe (par ex. en définissant des groupes de types qui partagent certaines propriétés).

Tu peux déjà obtenir cela avec :
  • côté structurel, le sous-typage des types objets OCaml (tu exprimes la présence d’une propriété par l’existence d’une méthode donnée; et ça ne demande pas forcément d’utiliser des objets au runtime), ou les modules ML (au lieu de fonctions dépendant d’un groupe de types, tu as des foncteurs dépendant d’une interface), même si cette dernière solution peut être moins flexible (en absence de modules first-class); plus généralement les solutions à base de sous-typage sont intéressantes et s’inscrivent dans le cadre que tu donnes.
  • côté nominal (et encore, ça se discute), les type-classes de Haskell ou Clean sont aussi très proches de ce que tu cherches : elles permettent effectivement de poser des contraintes sur les types qui instancient les variables de types : Foo a => a -> a est le type des fonctions a -> a restreintes aux instances de la classe Foo. On peut en fait généraliser à un cadre de "contraintes" plus large que les type classes, et c’est ce que fait par exemple le récent papier Haskell Type Constraints Unleashed (attention, connaissance de base de Haskell nécessaire pour la lecture).
Aucune de ces solutions ne s’est imposée pour l’instant, elles ont toutes des avantages et défauts et on fait encore de la recherche dessus : je ne veux pas dire que le problème que tu évoques est complètement réglé. Cependant, on a quand même pas mal d’outils pour faire ce dont tu parles, donc ce n’est plus non plus de l’ordre du "rêve lointain".
[ tag:blog.huoc.org,2009-12-08:1260293423.9434 ]

Nouveau commentaire