• Aucun résultat trouvé

A.2 Système de types du langage mCaml

A.2.5 Le typage des expressions

Le typage des expressions associe un type à une expression. Pour faire, on introduit un environ-nement de typage des expressions, que nous notons E, en plus des environenviron-nements précédemment utilisés. Cet environnement E associe des noms de variables à des schémas de type.

Variables Pour avoir le type d’une variable, il faut récupérer le schéma de type associé à la variable dans l’environnement de typage des expressions, et en prendre une instance. Par exemple, si x est la

fonction identité définie parlet x = fun x1 -> x1, son schéma de type pourra être ∀α.α ->α. Son

instance sera alors le type mCaml α ->α (sous-entendu ∃α.α ->α).

Var-inst

E, T, C, R ` x : I nstanciate(E(x))

Nombres entiers Soitn un nombre entier. Alors son type est int. Integer

E, T, C, R ` n : int

Booléens Les deux booléenstrue et false sont de type bool.

True

E, T, C, R ` true : bool

False

E, T, C, R ` false : bool

Constructeurs constants Un constructeur constant est un constructeur de type variant sans paramètre. Soit C un constructeur. Le nom sans paramètres de son type peut être retrouvé dans

l’environnement C à l’aide de C(C). Ensuite T permet d’obtenir le nom complet (avec les para-mètres éventuels de type) avec T(C(C)). C’est ce type instancié qui est le type donné au construc-teur. L’instantiation est nécessaire car le type est éventuellement paramétré. Le type de C est donc Instanciate(T(C(C))).

constant-Constructor-inst

E, T, C, R ` (∅ ⇒t) , I nstanciate(C(C)) E, T, C, R ` C : t

Constructeurs non-constants Le typage d’un constructeurC avec une expression e en

pa-ramètre demande au constructeur d’attendre effectivement un argument d’un type compatible avec celui dee. On récupère les informations de type de C à l’aide de C(C), et on doit obtenir un couple

(tσ, tσe) dont le premier élément indique le nom non paramétré du type d’appartenance de C et dont le second élément indique le type de l’argument attendu. Ensuite, T(tσ) permet de retrouver le nom complet du type à qui le constructeur appartient. L’instantiation se fait alors en concordance avec le type de l’argument, on obtient ainsi(t, te) , Instanciate(T(tσ), tσ e). Enfin, teest le type dee, et t est

le type deC(e).

Constructor-inst

E, T, C, R ` (tet) , Instanciate(C(C)) E, T, C, R ` e : te

E, T, C, R ` C(e) : t

Enregistrements Considérons l’expression{f1=e1;. . . ; fn=en} qui est un enregistrement et nommons-lae. Nous commençons par vérifier que chacun des champs d’enregistrement est associé

au même type tρ dans l’environnement R. Ensuite, nous prenons récupérons une instance t du type complet correspondant à tρ qui est T(tρ), ce qui donne t , Instanciate(T(tρ)). Le type t contient des informations et peut être utilisé comme un environnement pour récupérer les informations dont nous avons besoin (cf. la définition d’un type enregistrement plus haut). Le type t contient en effet

l’ensemble des champs de l’enregistrement avec leurs types associés instanciés ainsi que le nom com-plet instancié du typetρ qui est alorst(type). On vérifie alors que chacune des expressions a le type

du champ auquel elle a été liée. Ensuite on vérifie l’exhaustivité des champs (on fait l’appel pour que personne ne manque) et l’unicité des champs (on ne veut pas qu’un champ apparaisse plusieurs fois). Ainsi, pour chacun des champsf de T(tρ)\(type, tρ)1(donc là il ne reste plus que les champs associés à leurs types), il doit exister un unique champf0 (associé à un quelconque type) tel quef = f0. Enfin, le type mCaml de e est alors t(type), mais on mettra directement t dans l’environnement de typage des expressions pour pouvoir disposer ultérieurement des informations sur les types instanciés des champs de l’enregistrement2.

1. on prend T(tρ) plutôt que t pour pouvoir facilement exprimer la privation du premier champ (type, tρ), car le premier champ det n’est pas (type, tρ) mais une instance. En effet, nous n’utilisons que les noms des champs de l’enregistrement.

2. Une autre façon de faire est d’introduire un environnement supplémentaire pour associer le typet(type) à t, mais cela

Record-inst

lete , { f1=e1;. . . ; fn=en} E, T, C, R ` tρ, R(f1) . . . E, T, C, R ` R(f1) = . . . = R(fn) E, T, C, R ` ∀(f , _) ∈ (t\(type, tρ)), ∃!(f0, _) ∈ e, f = f0

E, T, C, R ` t , I nstanciate(T(tρ)) E, T, C, R ` e1: t(f1) . . . E, T, C, R ` en: t(fn) E, T, C, R ` e : t

Accès en lecture aux champs d’enregistrements Si e est de type t et t(f ) est valide (ce

qui veut dire quet est un type qui contient le champ f ), alors e.f est de type t(f ) (c’est-à-dire le type

associé àf dans t). L’accès à un champ inexistant ou mal typé ne doit pas arriver. Record-Access

E, T, C, R ` e : t E, T, C, R ` t(f ) E, T, C, R ` e.f : t(f )

Accès en écriture aux champs d’enregistrements Pour l’expression(e1.f <- e2), si e1 est de type t1,f est bien un champ mutable du type t1, et e2 est bien du type du champ f , alors

l’expression est de typeunit.

Record-Modify

E, T, C, R ` e1: t1 E, T, C, R ` R(mutable f ) E, T, C, R ` t1(f ) = t2 E, T, C, R ` e2: t2 E, T, C, R ` (e1.f <- e2) : unit

λ-abstraction Pour l’expression(fun x -> e), si x est de type t1,e est de type t2, alors l’expres-sion est de type(t1->t2).

Abstraction

(x : t1)CE, T, C, R ` e : t2

E, T, C, R ` (fun x -> e) : (t1->t2)

Application Pour l’expression(e1 e2), si e1 est de typet1 ->t2 ete2 est de typet1, alors l’ex-pression est de typet2.

Application

E, T, C, R ` e1: t1->t2 E, T, C, R ` e2: t1 E, T, C, R ` (e1e2) : t2

Liaison locale Les liaisons sont les endroits où se décide la généralisation du type d’une pression. Si l’expression est expansive, alors on ne généralise pas, sinon on généralise. En fait, une ex-pression est expansive lorsque sa généralisation peut potentiellement entraîner une erreur de typage. Par exemple, l’application est expansive notamment parce que si elle retourne une valeur mutable, il ne vaut mieux pas qu’elle soit affectable par la suite avec des valeurs de types différents.

Let-in-gen

E, T, C, R ` e1: t1 E, T, C, R ` Expansive(e1) = ⊥ (x, Generalize(E, t1))CE, T, C, R ` e2: t2 E, T, C, R ` (let x = e1ine2) : t2

Let-in

E, T, C, R ` e1: t1 E, T, C, R ` Expansive(e1) = > (x, t1)CE, T, C, R ` e2: t2 E, T, C, R ` (let x = e1ine2) : t2

Rec-in-gen

(x1, t2->t1)C(x2, t2)CE, T, C, R ` e1: t1 (x1, Generalize(E, t2->t1))CE, T, C, R ` e2: t E, T, C, R ` (let rec x1= funx2->e1ine2) : t

Valeur du type unit

Unit

E, T, C, R ` () : unit

Séquence Pour la séquencee1;e2, on choisit d’obliger le type dee1à être de typeunit. Sie1

n’est pas de typeunit, il suffira pour le programmeur de le transtyper.

Sequence

E, T, C, R ` e1: unit E, T, C, R ` e2: t E, T, C, R ` (e1;e2): t

Conditionnelle La conditionnelle oblige la condition à être de typeboolet ses deux branches à être de même type.

Conditional

E, T, C, R ` e1: bool E, T, C, R ` e2: t E, T, C, R ` e3: t E, T, C, R ` (if e1thene2elsee3) : t

Conjonction et disjonction séquentielles La conjonction et la disjonction ne s’appliquent qu’à des expressions booléennes.

Sequential-Conjunction E, T, C, R ` e1: bool E, T, C, R ` e2: bool E, T, C, R ` (e1&&e2) : bool Sequential-Disjunction E, T, C, R ` e1: bool E, T, C, R ` e2: bool E, T, C, R ` (e1||e2) : bool

Négation booléenne La négation booléenne ne s’applique qu’aux booléens.

Negation

E, T, C, R ` e : bool E, T, C, R ` not(e) : bool

Boucle itérative bornée On a choisit d’obliger le corps de la boucle à être de typeunit.

For

E, T, C, R ` e1: int E, T, C, R ` e2: int (x : int) C E, T, C, R ` e3: unit E, T, C, R ` (for x = e1toe2doe3done) : unit

Boucle itérative non bornée On a choisi d’obliger le corps de la boucle à être de typeunit.

While

E, T, C, R ` e1: bool E, T, C, R ` e2: unit E, T, C, R ` (while e1doe2done) : unit

Les définitions des exceptions enrichissent l’environnement de typage des constructeurs. On obtient donc en retour un nouvel environnement de typage des constructeurs.

Exception1

T, C ` exception C ; (C, exn)CC

Exception2

T, C ` T(t)

T, C ` exception C of t ; (C, (exn, t))CC

Typage des expressions utilisant explicitement les exceptions

Try E, T, C, R ` e1: t (x, exn)CE, T, C, R ` e2: t E, T, C, R ` (try e1withx -> e2) : t Raise E, T, C, R ` e : exn E, T, C, R ` raise e : I nstanciate(∀α.α)

Typage du filtrage par motifs

Le typage des motifs nécessite des règles de typage particulières pour les filtres-motifs du fait qu’ils enrichissent l’environnement et qu’ils peuvent être imbriqués. Voici donc les règles de typage des filtres.

Une variable est associée à un type inconnu et cette association est rendue dans l’environnement résultant. Une constante est simplement associée à son type.

pat-Var t = Instanciate(∀α.α) E, T, C, R ` x : t  (x, t)CE pat-const-Integer E, T, C, R ` n : int  E pat-const-Unit E, T, C, R ` () : unit  E pat-const-True E, T, C, R ` true : bool  E pat-const-False E, T, C, R ` false : bool  E pat-const-Constructor E, T, C, R ` (∅ ⇒t) , I nstanciate(C(C)) E, T, C, R ` C : t  E

Comme le constructeur non constant contient un autre motif, c’est l’autre motif qui se charge d’éventuellement enrichir l’environnement. On vérifie bien sûr que le type du constructeur est valide, y compris pour son argument.

pat-Constructor E, T, C, R ` (tat) , Instanciate(C(C)) E, T, C, R ` p : ta  E0 E, T, C, R ` C(p) : t  E0

Le filtrage des enregistrements contraint tous les champs à appartenir à la même définition de type et à être associés à des motifs du bon type. Un champ ne peut pas apparaître plusieurs fois mais des champs peuvent être omis.

pat-Record E, T, C, R ` tρ,R(f1) . . . E, T, C, R ` tρ,R(fn) E, T, C, R ` t,I nstanciate(T(tρ)) E, T, C, R ` p1: t(f1)  T1 . . . E, T, C, R ` pn: t(fn)  En (E1 . . . ∩ En) = E E, T, C, R ` ` { f1=p1; . . . ; fn=pn}: t  (E1. . . ∪ En)

Le typage du filtrage dans son ensemble Chaque filtre des branches doit être de même type que le type de l’expression dont la valeur est filtrée. Chaque expression des branches doit être de même type. Match E, T, C, R ` e : t0 E, T, C, R ` p1: t0  E1 . . . E, T, C, R ` pn: t0  En E1, T, C, R ` e1: t . . . En, T, C, R ` en: t E ` (match e with p1->e1| . . . | pn->en) : t