• Aucun résultat trouvé

Nous allons à présent dénir une relation de comparaison polymorphe entre schémas de types. Elle est basée sur le sous-typage entre types bruts, mais tient compte du fait qu'un schéma de types contient des variables universellement quantiées. Cette relation joue un rôle fondamental dans notre théorie, puisqu'elle permettra ensuite de justier l'ensemble des transformations et des simplications que nous introduirons sur les schémas de types.

La dénition de cette relation est fort simple. Elle provient de l'idée qu'un schéma de types n'est en fait qu'une façon de décrire un ensemble de typages bruts, que nous appellerons sa dénotation. Pour comparer deux schémas, il sut de comparer leurs dénotations, par simple inclusion ensembliste.

Quelle est la dénotation d'un schéma=A) jC? En d'autres termes, quels typages bruts ce schéma représente-t-il? Au moins toutes ses instances brutes, c'est-à-dire tous les typages bruts obtenus par substitution. Bien sûr, il n'est légal d'appliquer une substitution brute à que si elle vérie les contraintes de C; donc, les instances brutes de sont les

4.2. COMPARAISONDE SCHÉMAS 47 (A)), oùparcourt les solutions deC. Qui plus est, on remarque que les typages bruts sont ordonnés par sous-typage; étant donné un typage brut correct, le cône qu'il engendre ne contiendra également que des typages corrects.

Formalisons à présent cette discussion.

Dénition 4.4

Les contextes bruts sont dénis par A ::= ?

j A;x:

où est un type brut. La relation de sous-typage est étendue, point par point, aux contextes bruts de même domaine. Un typage brut est de la forme

A)

où A est un contexte brut et un type brut. La relation de sous-typage est étendue aux typages bruts, de façon contravariante pour le contexte et covariante pour le type.

Dénition 4.5

Soit A) j C un schéma de types. Sa dénotation est l'union des cônes engendrés par ses instances brutes, c'est-à-dire

fA0 )0;9`C (A))A0 )0g où(A)) représente le typage brut(A))().

Dénition 4.6

Etant donnés deux schémas de types 1 et 2, on dit que le premier est plus général que le second, et on écrit 182, ssi la dénotation du premier contient celle du second.

En d'autres termes, 1 est plus général que 2 ssi pour toute instance brute de 2, il existe une instance brute de1 qui lui est inférieure. De façon formelle,

(A1)1jC1)8(A2)2jC2) est donc équivalent à

82`C2 91`C1 1(A1)1)2(A2)2) On écrira =80 lorsque80 et0 8.

Enn, pour pouvoir faire référence de façon succincte aux contraintes engendrées par la comparaison de deux schémas, nous donnons la dénition suivante :

Dénition 4.7

La notationAA0, oùAetA0 sont deux contextes de même domaine, est dénie par

??=?

(A;x:)(A0;x:0) = (AA0)[subc( 0)

SoientA) jC etA0)0jC0 deux schémas. La notationA) A0)0 représentera l'ensemble (A0A)[subc( 0).

La dénition de la relation 8 est due à Trifonov et Smith [49]. On remarque qu'elle généralise à la fois les assertions de solubilité et d'implication. En eet, l'assertion9`C, qui exprime queCest soluble, peut s'écrire>jC8>j?. Quant à l'assertionC , elle est équivalente à!j?8! jC. La décidabilité de l'implication de contraintes étant actuellement un problème ouvert, il en va de même de la comparaison entre schémas de types. Nous donnerons cependant, au chapitre 9 un algorithme de décision incomplet pour cette dernière. Comme on peut s'y attendre, cet algorithme généralisera à la fois l'algorithme

48 CHAPITRE4. SCHÉMASDE TYPES de clôture, qui permet de décider la solubilité des graphes de contraintes, et l'algorithme (incomplet) d'implication de contraintes.

Dans [43], nous avions présenté une relation de comparaison moins puissante, qui ne tenait pas compte du fait que certaines variables étaient universellement quantiées. Elle était dénie à l'aide de la relation d'implication de contraintes. Elle est à présent inutile, sauf dans la preuve de correction du typage, où elle joue un rôle auxiliaire (cf. dénition 5.8).

Elle est susante pour justier les simplications à base de substitutions. Cependant, du fait qu'elle ne considère pas les variables comme quantiées, elle interdit de nombreuses opérations; par exemple les renommages, mais aussi l'élimination des variables inaccessibles, qui était justiée dans [43] par une réécriture de l'ensemble de la dérivation de typage.

C'est pourquoi Trifonov et Smith introduisent la relation8: les renommages, ainsi que le dépoussiérage (qui généralise l'élimination des variables inaccessibles) peuvent à présent se justier par une simple application de la règle de sous-typage. On intègre ainsi au système des propriétés qui auparavant étaient méta-théoriques.

Chapitre 5

Système de typage

L

a raison d'être première d'un système de typage est d'éliminer tous les pro-grammes qui provoquent une erreur à l'exécution. (La seconde pourrait être l'utili-sation des types à des ns de documentation la simplication entre alors en jeu mais cela ne nous intéresse pas ici.)

Un système de typage consiste habituellement en un prédicat dit jugement de typage, à trois paramètres , eet , noté `e:. Il est déni comme le plus petit prédicat stable par un certain jeu de règles de typage, c'est-à-dire qu'un jugement de typage est valide si et seulement si il peut être dérivé à l'aide de ces règles. Un programmee sera alors considéré comme correct si et seulement si il est bien typé dans l'environnement vide, c'est-à-dire si le prédicat?`e: est vérié pour un certain.

Un système de typage doit être sûr : aucun programme déclaré correct ne doit provoquer d'erreur à l'exécution. Pour donner un sens à cette propriété, il faut donner une spécication formelle de l'exécution. Nous donnons donc une sémantique opérationnelle, qui présente l'exécution comme une série de réductions, c'est-à-dire de réécritures du texte du programme.

Enn, pour présenter un intérêt pratique, un système de typage doit être décidable : on veut pouvoir vérier automatiquement qu'un programme est bien typé. Mieux, ici, on souhaite réaliser l'inférence de types, qui consiste à déterminer si un programme est bien typé et à découvrir son type sans aucune indication de la part du programmeur. Le système de typage devra alors être accompagné d'une description de l'algorithme d'inférence. Pour permettre la programmation modulaire, il faudra que le type inféré soit le (ou plutôt un) type le plus général du programme fourni. Cela nécessite qu'un tel type existe en général, c'est-à-dire que le système de typage admette des types principaux.

Dans ce chapitre, nous exposons notre système de typage et montrons qu'il répond à tous les critères généraux mentionnés ci-dessus. Nous dénissons d'abord rapidement le langage (section 5.1). Vient ensuite, après quelques préliminaires techniques (section 5.2), l'exposé du système de typage (section 5.3). La section 5.4 décrit un second système de typage, dit simple, équivalent au premier en termes de programmes acceptés, mais moins puissant en termes de jugements de typage corrects. Ce système sera utilisé dans la preuve de correction. La section 5.5 décrit un troisième système, lui aussi équivalent au précédent mais plus restreint, et qui constitue en fait une spécication de l'algorithme d'inférence. Une fois les trois systèmes présentés, nous montrons leur équivalence (section 5.6); de plus, nous montrons l'existence de types principaux et vérions qu'ils sont calculés par l'algorithme d'inférence. Enn, la section 5.7 se charge de dénir la sémantique et de vérier que le système de typage est correct vis-à-vis de celle-ci.

5.1 Langage

Le langage qui nous intéresse ici est le noyau de ML, c'est-à-dire un-calcul doté d'une constructionlet. Pour plus de simplicité, nous séparons les identicateurs liés parde ceux

49

50 CHAPITRE 5. SYSTÈMEDE TYPAGE liés parlet, en les plaçant dans deux classes syntaxiques distinctes.

Dénition 5.1

On suppose donné un ensemble dénombrable de let-identicateurs, notés X;Y;::: Les expressions sont dénies par

e::=xjx:ejeejX jletX =ein e