Notations extensibles et langage de surface

On appelle surcharge (overloading en anglais) le fait d'utiliser un même nom ou une même notation pour désigner des fonctions différentes. La surcharge est tellement usuelle en mathématiques qu'on aurait presque tendance à l'oublier. Par exemple, x + y a un sens différent selon que x et y soient des entiers, des vecteurs, des matrices, des fonctions, etc. La plupart des langages de programmation ont suivi cette présentation. Ainsi, dans le langage C, on peut écrire a + b pour additioner des entiers ou des flottants. Certains langages vont au-delà des opérateurs de prédéfinis. C'est le cas en C++, où l'on peut écrire t[i] pour accéder au i-ème élément de n'importe quelle structure de données : l'opérateur crochet peut être librement défini par l'utilisateur pour chaque type.

Ce principe s'applique également pour des fonctions nommées, par exemple t.size() appelle la fonction size associée au type de la structure t, sans faire référence au nom de la structure de donnée en écrivant array::size ou bien Array.size, selon la syntaxe. La surcharge apparaît aussi pour l'accès au champ des records, par exemple r.x permet d'accéder au champ x, qui peut avoir des types différents selon le type du record r. Dans un langage fonctionnel, la surchage serait de plus utile pour pouvoir utiliser le même nom de constructeur dans différents types inductifs vivant dans le même scope.

Le problème de la surcharge apparaît en Coq non seulement lorsqu'on écrit des programmes, mais encore davantage lorsqu'on formalise des mathématiques. En effet, l'écriture d'expressions mathématiques sans surcharge aboutit très rapidement à des formules illisibles en pratique par un humain. Dans le cadre d'un système interactif, le problème est encore plus important au moment de l'écriture parce l'utilisateur doit retrouver une notation peu naturelle pour une opération qu'il aurait naturellement écrite avec une notation surchagée. Par exemple, on peut décider d'utiliser *: au lieu de * pour la multiplication d'un vecteur par un scalaire, mais l'utilisateur doit retrouver ce symbole *: qui est difficile à mémoriser.

En Coq, le mécanisme des typeclasses ou des canonical structures permet, dans une certaine mesure, de bénéficier de surcharge. Avec ce mécanisme, l'addition de deux entiers a + b s'élabore vers l'expression plus Z plus_inst_Z a b, où Z est le type des entiers, et plus_inst_Z est l'instance qui enregistre le fait que l'opérateur d'addition sur les entiers est Z.add. Pour faire court, là où l'on s'attendrait naïvement à ce que l'expression a + b soit une notation pour le terme Z.add a b, celle-ci s'élabore en réalité vers le terme plus Z plus_inst_Z a b. Ce dernier terme est équivalent (convertible) avec Z.add a b, mais il n'est pas syntaxiquement égal. Ce décalage est un obstacle important pour des opérations de réécriture, en particulier.

En résumé, il y aurait énormément de bénéfices à pouvoir bénéficier d'un mécanisme de surcharge en Coq. Le mécanisme de surchage proposé par C++ donne des pistes, mais il n'explique pas comment gérer les constantes (déterminer le type d'un symbole comme zéro ou l'ensemble vide), et n'explique pas comment faire interagir la résolution de la surcharge avec l'inférence de types réalisée par un algorithme d'unification. En particulier, il y a des difficultés pour traiter correctement les appels à des fonctions d'ordre supérieur. Des algorithmes de résolution de la surcharge basés sur du typage bidirectionnel ont été proposés dans le langage ADA ainsi que dans le prouveur PVS, et ont démontré leur passage à l'échelle industrielle. Ils fournissent des pistes intéressantes, néanmoins ces systèmes ne traitent pas le cas des fonctions polymorphes, ni des types dépendants.

L'objectif de notre travail est de spécifier les détails et d'implémenter un algorithme de typage bidirectionnel qui soit capable de résoudre la surchage de manière :

On portera par ailleurs un soin particulier à produire des messages d'erreurs compréhensibles et informatifs dans les cas où l'algorithme de résolution de la surcharge rejette le terme fourni.