Ecole Normale Sup´erieure´
Langages de programmation et compilation
Jean-Christophe Filliˆatre typage
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 1
typage
si j’´ecris l’expression
"5" + 37 dois-je obtenir
• une erreur `a la compilation ? (OCaml, Rust, Go)
• une erreur `a l’ex´ecution ? (Python, Julia)
• l’entier 42 ? (Visual Basic, PHP)
• la chaˆıne"537"? (Java, Scala, Kotlin)
• un pointeur ? (C, C++)
• autre chose encore ?
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 4
typage
et si on additionne deux expressions arbitraires e1 + e2
comment d´eterminer si cela est l´egal et ce que l’on doit faire le cas
´ech´eant ?
la r´eponse est letypage, une analyse qui associe untype`a chaque valeur/expression, dans le but de rejeter les programmes incoh´erents
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 5
`a quel moment ?
certains langages sonttyp´es dynamiquement: les types sont associ´es auxvaleurset utilis´es pendant l’ex´ecutiondu programme
exemples : Lisp, PHP, Python, Julia
d’autres sonttyp´es statiquement: les types sont associ´es aux expressionset utilis´es pendant lacompilationdu programme
exemples : C, Java, OCaml, Rust, Go
c’est ce second cas que l’on consid`ere dans le cours d’aujourd’hui
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 6
remarque
un langage peut utiliser`a la foisdes notions de typage statique et de typage dynamique
on le verra avec l’exemple de Java dans un autre cours
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 7
slogan
well typed programs do not go wrong
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 8
objectifs du typage
• le typage doit ˆetred´ecidable
• le typage doit rejeter les programmes absurdes comme 1 2, dont l’´evaluation ´echouerait ; c’est lasˆuret´e du typage
• le typage ne doit pas rejeter trop de programmes non-absurdes, i.e.le syst`eme de types doit ˆetreexpressif
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 9
plusieurs solutions
1.toutes les sous-expressions sont annot´ees par un type
fun(x:int)→let(y:int) = (+ :)(((x:int),(1 :int)) :int×int)in facile de v´erifier mais trop fastidieux pour le programmeur
2.annoter seulement les d´eclarations de variables (Pascal, C, Java, etc.) fun(x:int)→let(y:int) = +(x,1)iny
3.annoter seulement les param`etres de fonctions fun(x:int)→lety= +(x,1)iny
4.ne rien annoter⇒inf´erencecompl`ete (OCaml, Haskell, etc.)
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 10
propri´et´es attendues
un algorithme de typage doit avoir les propri´et´es de
• correction: si l’algorithme r´epond “oui” alors le programme est effectivement bien typ´e
• compl´etude: si le programme est bien typ´e, alors l’algorithme doit r´epondre “oui”
et ´eventuellement de
• principalit´e: le type calcul´e pour une expression est le plus g´en´eral possible
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 11
typage de mini-ML
consid´erons le typage de mini-ML 1.typage monomorphe
2.typage polymorphe, inf´erence de types
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 12
mini-ML
rappel
e ::= x identificateur
| c constante (1, 2, . . .,true, . . .)
| op primitive (+,×,fst, . . .)
| funx→e fonction
| e e application
| (e,e) paire
| letx=eine liaison locale
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 13
typage monomorphe de mini-ML
on se donne destypes simples, dont la syntaxe abstraite est τ ::= int|bool| . . . types de base
| τ→τ type d’une fonction
| τ×τ type d’une paire
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 14
jugement de typage
lejugementde typage que l’on va d´efinir se note Γ`e:τ
et se litdans l’environnement Γ, l’expressione a le typeτ
l’environnement Γ associe un type Γ(x) `a toute variablexlibre danse
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 15
r`egles de typage
Γ`x: Γ(x) Γ`n:int...
Γ`+ :int×int→int...
Γ +x:τ1`e:τ2
Γ`funx→e:τ1→τ2
Γ`e1:τ0→τ Γ`e2:τ0 Γ`e1e2:τ Γ`e1:τ1 Γ`e2:τ2
Γ`(e1,e2) :τ1×τ2
Γ`e1:τ1 Γ +x:τ1`e2:τ2
Γ`letx=e1ine2:τ2
Γ +x:τ est l’environnement Γ0d´efini par Γ0(x) =τ et Γ0(y) = Γ(y) sinon
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 16
exemple
... ...
x:int`(x,1) :int×int x:int`+(x,1) :int
∅ `funx→+(x,1) :int→int
...`f:int→int ...`2 :int f:int→int`f 2 :int
∅ `letf =funx→+(x,1)inf 2 :int
expressions non typables
en revanche, on ne peut pas typer le programme 1 2 Γ`1 :τ0→τ Γ`2 :τ0
Γ`1 2 :τ ni le programmefunx→x x
Γ +x:τ1`x:τ3→τ2 Γ +x:τ1`x:τ3 Γ +x:τ1`x x:τ2
Γ`funx→x x:τ1→τ2
carτ1=τ1→τ2n’a pas de solution (les types sont finis)
plusieurs types possibles
on peut montrer
∅ `funx→x:int→int mais aussi
∅ `funx→x:bool→bool
attention: ce n’est pas du polymorphisme
pour une occurrence donn´ee defunx→xil fautchoisirun type
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 19
plusieurs types possibles
ainsi, le termeletf =funx→xin(f 1,f true) n’est pas typable car il n’y a pas de typeτ tel que
f:τ→τ`(f 1,f true) :τ1×τ2
en revanche,
((funx→x) (funx→x)) 42 est typable (exercice : le montrer)
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 20
primitives
en particulier, on ne peut pas donnerun typesatisfaisant `a une primitive commefst; il faudrait choisir entre
int×int→int int×bool→int bool×int→bool
(int→int)×int→int→int etc.
mais on peut en revanche donnerune r`eglede typage pour l’application defst:
Γ`e:τ1×τ2
Γ`fste:τ1
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 21
primitives
de mˆeme, on ne peut pas donner de type `aopfixde mani`ere g´en´erale, mais on peut donner une r`egle de typage pour son application
Γ`e:τ→τ Γ`opfixe:τ
et si on souhaite se limiter `a desfonctionsr´ecursives, on peut modifier ainsi
Γ`e: (τ1→τ2)→(τ1→τ2) Γ`opfixe:τ1→τ2
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 22
fonction r´ecursive
si on ajoutait plutˆot une constructionlet recdans le langage, cela donnerait
Γ +x:τ1`e1:τ1 Γ +x:τ1`e2:τ2
Γ`let recx=e1ine2:τ2 ou encore, pour des fonctions uniquement,
Γ + (f :τ→τ1) + (x:τ)`e1:τ1 Γ + (f :τ→τ1)`e2:τ2
Γ`let recf x=e1ine2:τ2
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 23
diff´erence entre r`egles de typage et algorithme de typage
quand on typefunx→e, comment trouve-t-on le type `a donner `ax? c’est toute la diff´erence entre lesr`egles de typage, qui d´efinissent la relation ternaire
Γ`e:τ
et l’algorithme de typagequi v´erifie qu’une certaine expressioneest bien typ´ee dans un certain environnement Γ
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 24
typage simple de mini-ML
consid´erons l’approche o`u seuls les param`etres de fonctions sont annot´es et programmons-la en OCaml
on se donne une syntaxe abstraite des types type typ =
| Tint
| Tarrow of typ * typ
| Tproduct of typ * typ
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 25
typage simple de mini-ML
le constructeurFunprend un argument suppl´ementaire type expression =
| Var of string
| Const of int
| Op of string
| Fun of string * typ * expression (* seul changement *)
| App of expression * expression
| Pair of expression * expression
| Let of string * expression * expression
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 26
typage simple de mini-ML
l’environnement Γ est r´ealis´e par une structure persistante en l’occurrence on utilise le moduleMapd’OCaml
module Smap = Map.Make(String) type env = typ Smap.t
(performances : arbres ´equilibr´es⇒insertion et recherche enO(logn))
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 27
typage simple de mini-ML
let rec type_expr env = function
| Const _ -> Tint
| Var x -> Smap.find x env
| Op "+" -> Tarrow (Tproduct (Tint, Tint), Tint)
| Pair (e1, e2) ->
Tproduct (type_expr env e1, type_expr env e2) pour la fonction, le type de la variable est donn´e
| Fun (x, ty, e) ->
Tarrow (ty, type_expr (Smap.add x ty env) e) pour la variable locale, il est calcul´e
| Let (x, e1, e2) ->
type_expr (Smap.add x (type_expr env e1) env) e2
(noter l’int´erˆet de la persistance deenv)
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 28
typage simple de mini-ML
les seules v´erifications se trouvent dans l’application
| App (e1, e2) -> begin match type_expr env e1 with
| Tarrow (ty2, ty) ->
if type_expr env e2 = ty2 then ty
else failwith "erreur : argument de mauvais type"
| _ ->
failwith "erreur : fonction attendue"
end
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 29
typage simple de mini-ML
exemples
# type_expr (Let ("f",
Fun ("x", Tint, App (Op "+", Pair (Var "x", Const 1))), App (Var "f", Const 2)));;
- : typ = Tint
# type_expr (Fun ("x", Tint, App (Var "x", Var "x")));;
Exception: Failure "erreur : fonction attendue".
# type_expr (App (App (Op "+", Const 1), Const 2));;
Exception: Failure "erreur : argument de mauvais type".
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 30
en pratique
• on ne fait pas
failwith "erreur de typage"
mais on indique l’origine du probl`eme avec pr´ecision
• on conserve les types pour les phases ult´erieures du compilateur
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 31
des arbres d´ecor´es
d’une part on d´ecore les arbresen entr´eedu typage avec une localisation dans le fichier source
type loc = ...
type expression =
| Var of string
| Const of int
| Op of string
| Fun of string * typ * expression
| App of expression * expression
| Pair of expression * expression
| Let of string * expression * expression
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 32
des arbres d´ecor´es
d’une part on d´ecore les arbresen entr´eedu typage avec une localisation dans le fichier source
type loc = ...
type expression = { desc: desc;
loc : loc;
}
and desc =
| Var of string
| Const of int
| Op of string
| Fun of string * typ * expression
| App of expression * expression
| Pair of expression * expression
| Let of string * expression * expression
signaler une erreur
on d´eclare une exception de la forme exception Error of loc * string on la l`eve ainsi
let rec type_expr env e = match e.desc with
| ...
| App (e1, e2) -> begin match type_expr env e1 with
| Tarrow (ty2, ty) ->
if type_expr env e2 <> ty2 then
raise (Error (e2.loc, "argument de mauvais type"));
...
signaler une erreur
et on la rattrape ainsi, par exemple dans le programme principal try
let p = Parser.parse file in let t = Typing.program p in ...
with Error (loc, msg) ->
Format.eprintf "File ’%s’, line ...\n" file loc;
Format.eprintf "error: %s@." msg;
exit 1
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 35
des arbres d´ecor´es
d’autre part, on d´ecore les arbresen sortiedu typage avec des types type texpression = {
tdesc: tdesc;
typ : typ;
}
and tdesc =
| Tvar of string
| Tconst of int
| Top of string
| Tfun of string * typ * texpression
| Tapp of texpression * texpression
| Tpair of texpression * texpression
| Tlet of string * texpression * texpression c’est unautre typed’expressions
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 36
typage du typage
la fonction de typage a donc un type de la forme val type_expr: expression -> texpression
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 37
des arbres typ´es
la fonction de typagereconstruitdes arbres, cette fois typ´es let rec type_expr env e =
let d, ty = compute_type env e in { tdesc = d; typ = ty }
and compute_type env e = match e.desc with
| Const n ->
Tconst n, Tint
| Var x ->
Tvar x, Smap.find x env
| Pair (e1, e2) ->
let te1 = type_expr env e1 in let te2 = type_expr env e2 in
Tpair (te1, te2), Tproduct (te1.typ, te2.typ)
| ...
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 38
sˆuret´e du typage
well typed programs do not go wrong
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 39
sˆuret´e du typage
on montre l’ad´equation du typage par rapport `a la s´emantique `a r´eductions Th´eor`eme (sˆuret´e du typage)
Si∅ `e:τ, alors la r´eduction de e est infinie ou se termine sur une valeur.
ou, de mani`ere ´equivalente, Th´eor`eme
Si∅ `e:τet e→? e0et e0irr´eductible, alors e0est une valeur.
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 40
sˆuret´e du typage
la preuve de ce th´eor`eme s’appuie sur deux lemmes Lemme (progression)
Si∅ `e:τ, alors soit e est une valeur, soit il existe e0tel que e→e0.
Lemme (pr´eservation)
Si∅ `e:τ et e→e0alors∅ `e0:τ.
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 41
progression
Lemme (progression)
Si∅ `e:τ, alors soit e est une valeur, soit il existe e0tel que e→e0. Preuve : par r´ecurrence sur la d´erivation∅ `e:τ
supposons par exemplee=e1e2; on a donc
∅ `e1:τ0→τ ∅ `e2:τ0
∅ `e1e2:τ on applique l’HR `ae1
• sie1→e10, alorse1e2→e10e2(cf lemme passage au contexte)
• sie1est une valeur, supposonse1=funx→e3(il y a aussi + etc.) on applique l’HR `ae2
• sie2→e02, alorse1e2→e1e20(mˆeme lemme)
• sie2est une valeur, alorse1e2→e3[x←e2]
(exercice : traiter les autres cas)
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 42
pr´eservation
on commence par de petits lemmes faciles Lemme (permutation)
SiΓ +x:τ1+y:τ2`e:τ et x6=y alorsΓ +y:τ2+x:τ1`e:τ (et la d´erivation a la mˆeme hauteur).
preuve : r´ecurrence imm´ediate
Lemme (affaiblissement)
SiΓ`e:τ et x6∈dom(Γ), alorsΓ +x:τ0`e:τ (et la d´erivation a la mˆeme hauteur).
preuve : r´ecurrence imm´ediate
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 43
pr´eservation
on continue par unlemme cl´e
Lemme (pr´eservation par substitution)
SiΓ +x:τ0`e:τ etΓ`e0:τ0alorsΓ`e[x←e0] :τ. preuve : par r´ecurrence sur la d´erivation Γ +x:τ0`e:τ
• cas d’une variablee=y
• six=yalorse[x←e0] =e0etτ=τ0
• six6=yalorse[x←e0] =eetτ= Γ(y)
• cas d’une abstractione=funy→e1
on peut supposery6=x,y6∈dom(Γ) etynon libre danse0(α-conversion) on a Γ +x:τ0+y:τ2`e1:τ1et donc Γ +y:τ2+x:τ0`e1:τ1 (permutation) ; d’autre part Γ`e0:τ0et donc Γ +y:τ2`e0:τ0 (affaiblissement)
par HR on a donc Γ +y:τ2`e1[x←e0] :τ1et donc Γ`(funy→e1)[x←e0] :τ2→τ1,i.e.Γ`e[x←e0] :τ
(exercice : traiter les autres cas)
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 44
pr´eservation
on peut enfin montrer Lemme (pr´eservation)
Si∅ `e:τ et e→e0alors∅ `e0:τ.
preuve : par r´ecurrence sur la d´erivation∅ `e:τ
• case=letx=e1ine2
∅ `e1:τ1 x:τ1`e2:τ2
∅ `letx=e1ine2:τ2
• sie1→e10, par HR on a∅ `e10:τ1et donc∅ `letx=e01ine2:τ2
• sie1est une valeur ete0=e2[x←e1] alors on applique le lemme de pr´eservation par substitution
• case=e1e2
• sie1→e10ou sie1valeur ete2→e02alors on utilise l’HR
• sie1=funx→e3ete2valeur alorse0=e3[x←e2]
et on applique l`a encore le lemme de substitution
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 45
sˆuret´e du typage
on peut maintenant prouver le th´eor`eme facilement Th´eor`eme (sˆuret´e du typage)
Si∅ `e:τet e→? e0et e0irr´eductible, alors e0est une valeur.
preuve : on ae→e1→ · · · →e0et par applications r´ep´et´ees du lemme de pr´eservation, on a donc∅ `e0:τ
par le lemme de progression,e0se r´eduit ou est une valeur
c’est donc une valeur
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 46
polymorphisme
il est contraignant de donner un type unique `afunx→xdans letf =funx→xin . . .
de mˆeme, on aimerait pouvoir donnerplusieurs typesaux primitives telles quefstousnd
une solution : lepolymorphisme param´etrique
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 47
polymorphisme param´etrique
on ´etend l’alg`ebre des types :
τ ::= int|bool| . . . types de base
| τ→τ type d’une fonction
| τ×τ type d’une paire
| α variable de type
| ∀α.τ type polymorphe
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 48
variables de types libres
on noteL(τ) l’ensemble des variables de typeslibresdansτ, d´efini par L(int) = ∅
L(α) = {α}
L(τ1→τ2) = L(τ1)∪ L(τ2) L(τ1×τ2) = L(τ1)∪ L(τ2)
L(∀α.τ) = L(τ)\ {α}
pour un environnement Γ, on d´efinit aussi L(Γ) = [
x∈dom(Γ)
L(Γ(x))
substitution de type
on noteτ[α←τ0] la substitution deαparτ0dansτ, d´efinie par int[α←τ0] = int
α[α←τ0] = τ0
β[α←τ0] = β siβ6=α
(τ1→τ2)[α←τ0] = τ1[α←τ0]→τ2[α←τ0] (τ1×τ2)[α←τ0] = τ1[α←τ0]×τ2[α←τ0]
(∀α.τ)[α←τ0] = ∀α.τ
(∀β.τ)[α←τ0] = ∀β.τ[α←τ0] siβ6=α
syst`eme F
les r`egles sontexactementles mˆemes qu’auparavant, plus Γ`e:τ α6∈ L(Γ)
Γ`e:∀α.τ
et Γ`e:∀α.τ
Γ`e:τ[α←τ0]
le syst`eme obtenu s’appelle lesyst`eme F(J.-Y. Girard / J. C. Reynolds)
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 51
exemple
x:α`x:α
`funx→x:α→α
`funx→x:∀α.α→α
...`f :∀α.α→α ...`f :int→int
... ...`f 1 :int
... ...`f true:bool f :∀α.α→α`(f 1,f true) :int×bool
`letf=funx→xin(f 1,f true) :int×bool
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 52
primitives
on peut maintenant donner un type satisfaisant aux primitives fst: ∀α.∀β.α×β→α
snd: ∀α.∀β.α×β→β opif : ∀α.bool×α×α→α opfix: ∀α.(α→α)→α
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 53
exercice
on peut construire une d´erivation de
Γ`funx→x x: (∀α.α→α)→(∀α.α→α) (exercice : le faire)
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 54
remarque
la conditionα6∈ L(Γ) dans la r`egle
Γ`e:τ α6∈ L(Γ) Γ`e:∀α.τ est cruciale
sans elle, on aurait
Γ +x:α`x:α Γ +x:α`x:∀α.α Γ`funx→x:α→ ∀α.α Γ`funx→x:∀α.α→ ∀α.α et on accepterait donc le programme
(funx→x) 1 2
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 55
une mauvaise nouvelle
pour des termes sans annotations, les deux probl`emes
• inf´erence: ´etant donn´eee, existe-t-ilτ tel que`e:τ?
• v´erification: ´etant donn´ese etτ, a-t-on`e:τ? ne sont pas d´ecidables
J. B. Wells.Typability and type checking in the second-order lambda-calculus are equivalent and undecidable, 1994.
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 56
le syst`eme de Hindley-Milner
pour obtenir une inf´erence de types d´ecidable, on va restreindre la puissance du syst`eme F
⇒le syst`eme deHindley-Milner, utilis´e dans OCaml, SML, Haskell, ...
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 57
le syst`eme de Hindley-Milner
on limite la quantification∀en tˆete des types (quantification pr´enexe)
τ ::= int|bool| . . . types de base
| τ→τ type d’une fonction
| τ×τ type d’une paire
| α variable de type
σ ::= τ sch´emas
| ∀α.σ
l’environnement Γ associe un sch´ema de type `a chaque identificateur et la relation de typage a maintenant la forme Γ`e:σ
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 58
exemples
dans Hindley-Milner, les types suivants sont toujours accept´es
∀α.α→α
∀α.∀β.α×β→α
∀α.bool×α×α→α
∀α.(α→α)→α
mais plus les types tels que
(∀α.α→α)→(∀α.α→α)
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 59
notation en OCaml
note : dans la syntaxe d’OCaml, la quantification pr´enexe est implicite
# fst;;
- : ’a * ’b -> ’a = <fun>
∀α.∀β.α×β→α
# List.fold_left;;
- : (’a -> ’b -> ’a) -> ’a -> ’b list -> ’a = <fun>
∀α.∀β.(α→β→α)→α→βlist→α
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 60
le syst`eme de Hindley-Milner
Γ`x: Γ(x) Γ`n:int...
Γ`+ :int×int→int...
Γ +x:τ1`e:τ2
Γ`funx→e:τ1→τ2
Γ`e1:τ0→τ Γ`e2:τ0 Γ`e1e2:τ Γ`e1:τ1 Γ`e2:τ2
Γ`(e1,e2) :τ1×τ2
Γ`e1:σ1 Γ +x:σ1`e2:σ2 Γ`letx=e1ine2:σ2
Γ`e:σ α6∈ L(Γ) Γ`e:∀α.σ
Γ`e:∀α.σ Γ`e:σ[α←τ]
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 61
le syst`eme de Hindley-Milner
on note que seule la constructionletpermet d’introduire un type polymorphe dans l’environnement
Γ`e1:σ1 Γ +x:σ1`e2:σ2
Γ`letx=e1ine2:σ2 en particulier, on peut toujours typer
letf =funx→xin(f 1,f true) avecf :∀α.α→αdans le contexte pour typer (f 1,f true)
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 62
le syst`eme de Hindley-Milner
en revanche, la r`egle de typage
Γ +x:τ1`e:τ2
Γ`funx→e:τ1→τ2
n’introduit pas un type polymorphe (sinonτ1→τ2serait mal form´e)
en particulier, on ne peut plus typer funx→x x
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 63
consid´erations algorithmiques
pour programmer une v´erification ou une inf´erence de type, on proc`ede par r´ecurrence sur la structure du programme
or, pour une expression donn´ee, trois r`egles peuvent s’appliquer : la r`egle du syst`eme monomorphe, la r`egle
Γ`e:σ α6∈ L(Γ) Γ`e:∀α.σ ou encore la r`egle
Γ`e:∀α.σ Γ`e:σ[α←τ]
comment choisir ? va-t-on devoir proc´eder par essais/erreurs ?
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 64
syst`eme de Hindley-Milner dirig´e par la syntaxe
nous allons modifier la pr´esentation du syst`eme de Hindley-Milner pour qu’il soitdirig´e par la syntaxe(syntax-directed),i.e., pour toute expression, au plus une r`egle s’applique
les r`egles ont la mˆeme puissance d’expression : tout terme clos est typable dans un syst`eme si et seulement si il est typable dans l’autre
syst`eme de Hindley-Milner dirig´e par la syntaxe
τ ≤Γ(x)
Γ`x:τ Γ`n:int... τ≤type(op) Γ`op:τ Γ +x:τ1`e:τ2
Γ`funx→e:τ1→τ2
Γ`e1:τ0→τ Γ`e2:τ0 Γ`e1e2:τ Γ`e1:τ1 Γ`e2:τ2
Γ`(e1,e2) :τ1×τ2
Γ`e1:τ1 Γ +x:Gen(τ1,Γ)`e2:τ2
Γ`letx=e1ine2:τ2
syst`eme de Hindley-Milner dirig´e par la syntaxe
deux op´erations apparaissent
• l’instanciation, dans la r`egle
τ≤Γ(x) Γ`x:τ
la relationτ ≤σse litτ est une instance deσet est d´efinie par
τ≤ ∀α1...αn.τ0 ssi ∃τ1...∃τn. τ=τ0[α1←τ1, ..., αn←τn]
exemple :int×bool→int≤ ∀α.∀β.α×β→α
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 67
syst`eme de Hindley-Milner dirig´e par la syntaxe
• et lag´en´eralisation, dans la r`egle
Γ`e1:τ1 Γ +x:Gen(τ1,Γ)`e2:τ2
Γ`letx=e1ine2:τ2 o`u
Gen(τ1,Γ) def= ∀α1...∀αn.τ1 o`u {α1, ..., αn}=L(τ1)\L(Γ)
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 68
exemple
α≤α x:α`x:α
∅ `funx→x:α→α
int→int≤∀α.α→α Γ`f:int→int ...
Γ`f 1 :int
bool→bool≤∀α.α→α Γ`f:bool→bool ... Γ`f true:bool Γ`(f 1,f true) :int×bool
∅ `letf =funx→xin(f 1,f true) :int×bool
avec Γ = ∅+f :Gen(α→α,∅)
= f :∀α.α→α
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 69
inf´erence de types pour mini-ML
pour inf´erer le type d’une expression, il reste des probl`emes
• dansfunx→e, quel type donner `ax?
• pour une variablex, quelle instance de Γ(x) choisir ?
il existe une solution :l’algorithme W(Milner, Damas, Tofte)
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 70
l’algorithme W
deux id´ees
• on utilise denouvelles variables de typespour repr´esenter les types inconnus
• pour le type dexdansfunx→e
• pour instancier les variables du sch´ema Γ(x)
• on d´etermine la valeur de ces variables plus tard, parunification entre typesau moment du typage de l’application
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 71
unification
soient deux typesτ1etτ2contenant des variables de typesα1, . . . , αn existe-t-il une instanciationf des variablesαi telle quef(τ1) =f(τ2) ? on appelle cela l’unification
exemple 1 :
τ1=α×β→int τ2=int×bool→γ
solution : α=int ∧ β=bool ∧ γ=int
exemple 2 :
τ1=α×int→α×int τ2=γ→γ
solution : γ=α×int
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 72
unification
exemple 3 :
τ1=α→int τ2=β×γ pas de solution
exemple 4 :
τ1=α→int τ2=α pas de solution
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 73
pseudo-code de l’unification
unifier(τ1, τ2) d´etermine s’il existe une instance des variables de types de τ1etτ2telle queτ1=τ2
unifier(τ, τ) = succ`es
unifier(τ1→τ10, τ2→τ20) =unifier(τ1, τ2) ; unifier(τ10, τ20) unifier(τ1×τ10, τ2×τ20) =unifier(τ1, τ2) ; unifier(τ10, τ20)
unifier(α, τ) = siα6∈ L(τ), remplacerαparτ partout sinon, ´echec
unifier(τ, α) =unifier(α, τ)
unifier(τ1, τ2) = ´echec dans tous les autres cas (pas de panique : on le fera en TD)
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 74
l’id´ee de l’algorithme W sur un exemple
consid´erons l’expression funx→+(fst x,1) – `axon donne le typeα1, nouvelle variable de type – la primitive + a le typeint×int→int – typons l’expression (fst x,1)
–fsta pour type le sch´ema∀α.∀β.α×β→α
– on lui donne donc le typeα2×β1→α2pour deux nouvelles variables – l’applicationfst ximpose d’unifierα1etα2×β1,⇒α1=α2×β1
– (fst x,1) a donc le typeα2×int
– l’application +(fst x,1) unifieint×intetα2×int,
⇒α2=int
au final, on obtient le typeint×β1→int,
et si on g´en´eralise (dans unlet) on obtient donc ∀β.int×β→int
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 75
pseudo-code de l’algorithme W
on d´efinit une fonctionW qui prend en arguments un environnement Γ et une expressioneet renvoie le type inf´er´e poure
• sieest une variablex,
renvoyer une instance triviale de Γ(x)
• sieest une constantec,
renvoyer une instance triviale de son type (penser `a [] :αlist)
• sieest une primitiveop,
renvoyer une instance triviale de son type
• sieest une paire (e1,e2), calculerτ1=W(Γ,e1) calculerτ2=W(Γ,e2) renvoyerτ1×τ2
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 76
l’algorithme W
• sieest une fonctionfunx→e1, soitαune nouvelle variable calculerτ=W(Γ +x:α,e1) renvoyerα→τ
• sieest une applicatione1e2, calculerτ1=W(Γ,e1) calculerτ2=W(Γ,e2) soitαune nouvelle variable unifier(τ1,τ2→α) renvoyerα
• sieestletx=e1ine2, calculerτ1=W(Γ,e1)
renvoyerW(Γ +x:Gen(τ1,Γ),e2)
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 77
r´esultats
Th´eor`eme (Damas, Milner, 1982)
L’algorithme W est correct, complet et d´etermine le type principal :
• si W(∅,e) =τ alors∅ `e:τ
• si∅ `e:τ alorsτ ≤ ∀α.W(¯ ∅,e)
Th´eor`eme (sˆuret´e du typage) Le syst`eme de Hindley-Milner est sˆur.
(Si∅ `e:τ, alors la r´eduction de e est infinie ou se termine sur une valeur.)
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 78
consid´erations algorithmiques
il existe plusieurs fa¸cons de r´ealiser l’unification
• en manipulant explicitement unesubstitution type tvar = int
type subst = typ TVmap.t
• en utilisant des variables de typesdestructives
type tvar = { id: int; mutable def: typ option; } il existe ´egalement plusieurs fa¸cons de coder l’algorithme W
• avec dessch´emas expliciteset en calculantGen(τ,Γ) type schema = { tvars: TVset.t; typ: typ; }
• avec desniveaux
Γ`n+1e1:τ1 Γ +x: (τ1,n)`ne2:τ2
Γ`nletx=e1ine2:τ2
cf. TD
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 79
extensions
on peut ´etendre mini-ML de nombreuses fa¸cons
• r´ecursion
• types construits (n-uplets, listes, types sommes et produits)
• r´ef´erences
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 80
r´ecursion
comme d´ej`a expliqu´e, on peut d´efinir let recf x=e1ine2=def
letf =opfix(funf →funx→e1)ine2
o`u
opfix:∀α.∀β.((α→β)→(α→β))→(α→β) de mani`ere ´equivalente, on peut donner la r`egle
Γ +f:τ→τ1+x:τ`e1:τ1 Γ +f :Gen(τ →τ1,Γ)`e2:τ2
Γ`let recf x=e1ine2:τ2
types construits
on a d´ej`a vu les paires
les listes ne posent pas de difficult´e []: ∀α. αlist
::: ∀α. α×αlist→αlist
Γ`e1:τ list Γ`e2:τ1 Γ +x:τ+y:τ list`e3:τ1
Γ`matche1with []→e2|::(x,y)→e3:τ1
se g´en´eralise ais´ement aux types sommes et produits
r´ef´erences
pour les r´ef´erences, on peut na¨ıvement penser qu’il suffit d’ajouter les primitives
ref: ∀α. α→αref : ∀α. αref→α := : ∀α. αref→α→unit
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 83
r´ef´erences
malheureusement, c’est incorrect !
letr=ref(funx→x)in r:∀α.(α→α)ref let =r:=(funx→x+ 1)in
!r true boum!
c’est le probl`eme dit desr´ef´erences polymorphes
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 84
r´ef´erences polymorphes
pour contourner ce probl`eme, il existe une solution extrˆemement simple,
`a savoir une restriction syntaxique de la constructionlet D´efinition (value restriction, Wright 1995)
Un programme satisfait le crit`ere de lavalue restrictionsi toute sous-expressionletest de la forme
letx=v1ine2
o`u v1est unevaleur.
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 85
r´ef´erences polymorphes
on ne peut plus ´ecrire
letr=ref(funx→x)in . . . mais on peut ´ecrire en revanche
(funr→. . .) (ref(funx→x)) o`u le type dern’est pas g´en´eralis´e
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 86
r´ef´erences polymorphes
en pratique, on continue d’´ecrireletr=ref . . . in . . . mais le type der n’est pas g´en´eralis´e
en OCaml, une variable non g´en´eralis´ee est de la forme’ a
# let x = ref (fun x -> x);;
val x : (’_a -> ’_a) ref
lavalue restrictionest ´egalement l´eg`erement relˆach´ee pour autoriser des expressions sˆures, telles que des applications de constructeurs
# let l = [fun x -> x];;
val l : (’a -> ’a) list = [<fun>]
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 87
r´ef´erences polymorphes
il reste quelques petits d´esagr´ements
# let id x = x;;
val id : ’a -> ’a = <fun>
# let f = id id;;
val f : ’_a -> ’_a = <fun>
# f 1;;
- : int = 1
# f true;;
This expression has type bool but is here used with type int
# f;;
- : int -> int = <fun>
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 88
r´ef´erences polymorphes
la solution : expanser pour faire apparaˆıtre une fonction,i.e., une valeur
# let f x = id id x;;
val f : ’a -> ’a = <fun>
(on parle d’η-expansion)
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 89
r´ef´erences polymorphes
en pr´esence du syst`eme de modules, la r´ealit´e est plus complexe encore
´etant donn´e un moduleM module M : sig
type ’a t
val create : int -> ’a t end
ai-je le droit de g´en´eraliser le type deM.create 17?
la r´eponse d´epend du type’a t: non pour un tableau, oui pour une liste, etc.
en OCaml, une indication devariancepermet de distinguer les deux type +’a t (* on peut g´en´eraliser *)
type ’a u (* on ne peut pas *) lireRelaxing the value restriction, J. Garrigue, 2004
Jean-Christophe Filliˆatre Langages de programmation et compilation typage 90