• Aucun résultat trouvé

Jean-ChristopheFilliˆatretypage Langagesdeprogrammationetcompilation ´EcoleNormaleSup´erieure

N/A
N/A
Protected

Academic year: 2022

Partager "Jean-ChristopheFilliˆatretypage Langagesdeprogrammationetcompilation ´EcoleNormaleSup´erieure"

Copied!
90
0
0

Texte intégral

(1)

Langages de programmation et compilation

Jean-Christophe Filliˆatre typage

(2)

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

(3)

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 le typage, une analyse qui associe un type`a chaque valeur/expression, dans le but de rejeter les programmes incoh´erents

(4)

`

a quel moment ?

certains langages sont typ´es dynamiquement: les types sont associ´es aux valeurs et utilis´es pendant l’ex´ecutiondu programme

exemples : Lisp, PHP, Python, Julia

d’autres sonttyp´es statiquement : les types sont associ´es aux expressions et 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

(5)

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

(6)

slogan

well typed programs do not go wrong

Jean-Christophe Filliˆatre Langages de programmation et compilation typage 8

(7)

• le typage doit ˆetred´ecidable

• le typage doit rejeter les programmes absurdes comme 1 2, dont l’´evaluation ´echouerait ; c’est la sˆuret´e du typage

• le typage ne doit pas rejeter trop de programmes non-absurdes, i.e. le syst`eme de types doit ˆetre expressif

(8)

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)in y

3. annoter seulement les param`etres de fonctions

fun(x :int)→lety = +(x,1)in y

4. ne rien annoter⇒ inf´erence compl`ete (OCaml, Haskell, etc.)

Jean-Christophe Filliˆatre Langages de programmation et compilation typage 10

(9)

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

(10)

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

(11)

rappel

e ::= x identificateur

| c constante (1, 2, . . .,true, . . .)

| op primitive (+,×,fst, . . .)

| funx →e fonction

| e e application

| (e,e) paire

| letx =e in e liaison locale

(12)

typage monomorphe de mini-ML

on se donne des types 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

(13)

le jugementde typage que l’on va d´efinir se note Γ`e :τ

et se lit dans l’environnement Γ, l’expressione a le type τ

l’environnement Γ associe un type Γ(x) `a toute variable x libre danse

(14)

r` egles de typage

Γ`x: Γ(x) Γ`n :int...

Γ`+ :int×int→int...

Γ +x:τ1`e :τ2 Γ`funx→e :τ1 →τ2

Γ`e10→τ Γ`e20 Γ`e1 e2

Γ`e11 Γ`e22 Γ`(e1,e2) :τ1×τ2

Γ`e11 Γ +x :τ1 `e22 Γ`letx =e1 in e22

Γ +x :τ est l’environnement Γ0 d´efini par Γ0(x) =τ et Γ0(y) = Γ(y) sinon

Jean-Christophe Filliˆatre Langages de programmation et compilation typage 16

(15)

... ...

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

(16)

expressions non typables

en revanche, on ne peut pas typer le programme 1 2 Γ`1 :τ0 →τ Γ`2 :τ0

Γ`1 2 :τ ni le programme funx →x x

Γ +x :τ1`x :τ3→τ2 Γ +x :τ1 `x :τ3

Γ +x:τ1`x x :τ2

Γ`funx→x x :τ1→τ2

car τ11 →τ2 n’a pas de solution (les types sont finis)

Jean-Christophe Filliˆatre Langages de programmation et compilation typage 18

(17)

on peut montrer

∅ `funx →x:int→int mais aussi

∅ `fun x→x :bool→bool

attention : ce n’est pas du polymorphisme

pour une occurrence donn´ee defunx →x il faut choisirun type

(18)

plusieurs types possibles

ainsi, le terme letf =funx→x in(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

(19)

comme fst; il faudrait choisir entre int×int→int int×bool→int bool×int→bool

(int→int)×int→int→int etc.

mais on peut en revanche donner une r`eglede typage pour l’application de fst:

(20)

primitives

de mˆeme, on ne peut pas donner de type `aopfix de mani`ere g´en´erale, mais on peut donner une r`egle de typage pour son application

Γ`e :τ →τ Γ`opfix e :τ

et si on souhaite se limiter `a des fonctions r´ecursives, on peut modifier ainsi

Γ`e : (τ1 →τ2)→(τ1 →τ2) Γ`opfixe :τ1 →τ2

Jean-Christophe Filliˆatre Langages de programmation et compilation typage 22

(21)

si on ajoutait plutˆot une constructionlet rec dans le langage, cela donnerait

Γ +x :τ1 `e11 Γ +x :τ1 `e22

Γ`let rec x=e1 in e22 ou encore, pour des fonctions uniquement,

Γ + (f :τ →τ1) + (x:τ)`e11 Γ + (f :τ →τ1)`e22 Γ`let rec f x=e1 in e22

(22)

diff´ erence entre r` egles de typage et algorithme de typage

quand on type funx →e, comment trouve-t-on le type `a donner `a x? c’est toute la diff´erence entre les r`egles de typage, qui d´efinissent la relation ternaire

Γ`e :τ

et l’algorithme de typage qui v´erifie qu’une certaine expressione est bien typ´ee dans un certain environnement Γ

Jean-Christophe Filliˆatre Langages de programmation et compilation typage 24

(23)

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

(24)

typage simple de mini-ML

le constructeur Fun prend 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

(25)

l’environnement Γ est r´ealis´e par une structure persistante en l’occurrence on utilise le module Mapd’OCaml

module Smap = Map.Make(String) type env = typ Smap.t

(performances : arbres ´equilibr´es ⇒insertion et recherche enO(logn))

(26)

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 de env)

Jean-Christophe Filliˆatre Langages de programmation et compilation typage 28

(27)

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

(28)

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

(29)

• 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

(30)

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

(31)

type loc = ...

type expression = { desc: desc;

loc : loc;

}

and desc =

| Var of string

| Const of int

| Op of string

| Fun of string * typ * expression

(32)

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"));

...

Jean-Christophe Filliˆatre Langages de programmation et compilation typage 34

(33)

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

(34)

des arbres d´ ecor´ es

d’autre part, on d´ecore les arbresen sortie du 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 type d’expressions

Jean-Christophe Filliˆatre Langages de programmation et compilation typage 36

(35)

la fonction de typage a donc un type de la forme val type_expr: expression -> texpression

(36)

des arbres typ´ es

la fonction de typage reconstruitdes 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

(37)

well typed programs do not go wrong

(38)

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→? e0 et e0 irr´eductible, alors e0 est une valeur.

Jean-Christophe Filliˆatre Langages de programmation et compilation typage 40

(39)

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 e0 tel que e →e0.

Lemme (pr´eservation)

Si ∅ `e :τ et e→e0 alors ∅ `e0:τ.

(40)

progression

Lemme (progression)

Si ∅ `e :τ, alors soit e est une valeur, soit il existe e0 tel que e →e0. Preuve : par r´ecurrence sur la d´erivation∅ `e :τ

supposons par exemplee =e1 e2; on a donc

∅ `e10→τ ∅ `e20

∅ `e1 e2 :τ on applique l’HR `ae1

• si e1 →e10, alors e1 e2→e10 e2 (cf lemme passage au contexte)

• si e1 est une valeur, supposonse1 =funx →e3 (il y a aussi + etc.) on applique l’HR `a e2

sie2e20, alorse1e2e1e20 (mˆeme lemme)

sie2est une valeur, alorse1 e2e3[x e2]

(exercice : traiter les autres cas)

Jean-Christophe Filliˆatre Langages de programmation et compilation typage 42

(41)

Lemme (permutation)

Si Γ +x:τ1+y:τ2`e :τ et x 6=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 x 6∈dom(Γ), alors Γ +x :τ0 `e :τ

(42)

pr´ eservation

on continue par un lemme cl´e

Lemme (pr´eservation par substitution)

Si Γ +x:τ0 `e :τ et Γ`e00 alorsΓ`e[x ←e0] :τ. preuve : par r´ecurrence sur la d´erivation Γ +x:τ0 `e :τ

• cas d’une variable e =y

six =y alorse[x e0] =e0 etτ=τ0

six 6=y alorse[x e0] =e etτ= Γ(y)

• cas d’une abstraction e =funy →e1

on peut supposery 6=x,y 6∈dom(Γ) ety non libre danse0 (α-conversion) on a Γ +x :τ0+y :τ2 `e11 et donc Γ +y:τ2+x:τ0 `e11

(permutation) ; d’autre part Γ`e00 et donc Γ +y :τ2`e00 (affaiblissement)

par HR on a donc Γ +y :τ2`e1[x ←e0] :τ1 et donc Γ`(fun y →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

(43)

Lemme (pr´eservation)

Si ∅ `e :τ et e→e0 alors ∅ `e0:τ.

preuve : par r´ecurrence sur la d´erivation∅ `e :τ

• cas e =letx =e1 in e2

∅ `e11 x :τ1 `e22

∅ `letx =e1 ine22

sie1e10, par HR on a∅ `e10 :τ1 et donc∅ `letx=e10 ine2:τ2

sie1est une valeur ete0=e2[xe1] alors on applique le lemme de pr´eservation par substitution

(44)

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→? e0 et e0 irr´eductible, alors e0 est une valeur.

preuve : on ae →e1 → · · · →e0 et par applications r´ep´et´ees du lemme de pr´eservation, on a donc∅ `e0

par le lemme de progression, e0 se r´eduit ou est une valeur

c’est donc une valeur

Jean-Christophe Filliˆatre Langages de programmation et compilation typage 46

(45)

il est contraignant de donner un type unique `afunx →x dans letf =funx→x in . . .

de mˆeme, on aimerait pouvoir donnerplusieurs types aux primitives telles que fstousnd

une solution : lepolymorphisme param´etrique

(46)

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

(47)

on note L(τ) l’ensemble des variables de types libres dans τ, 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(Γ) = [

L(Γ(x))

(48)

substitution de type

on note τ[α ←τ0] la substitution deα par τ0 dans τ, 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=α

Jean-Christophe Filliˆatre Langages de programmation et compilation typage 50

(49)

les r`egles sontexactement les mˆemes qu’auparavant, plus Γ`e:τ α6∈ L(Γ)

Γ`e:∀α.τ

et Γ`e:∀α.τ

Γ`e :τ[α←τ0]

le syst`eme obtenu s’appelle le syst`eme F (J.-Y. Girard / J. C. Reynolds)

(50)

exemple

x:α`x :α

`fun x→x :α→α

`fun x→x :∀α.α→α

...`f :∀α.α→α ...`f :int→int

... ...`f 1 :int

...

...`f true:bool f :∀α.α→α`(f 1,f true) :int×bool

`letf =funx→x in(f 1,f true) :int×bool

Jean-Christophe Filliˆatre Langages de programmation et compilation typage 52

(51)

on peut maintenant donner un type satisfaisant aux primitives fst : ∀α.∀β.α×β →α

snd : ∀α.∀β.α×β →β opif : ∀α.bool×α×α→α opfix : ∀α.(α→α)→α

(52)

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

(53)

Γ`e:τ α6∈ L(Γ) Γ`e:∀α.τ est cruciale

sans elle, on aurait

Γ +x:α `x :α Γ +x:α`x :∀α.α Γ`funx→x :α→ ∀α.α Γ`fun x→x :∀α.α→ ∀α.α et on accepterait donc le programme

(54)

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

(55)

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, ...

(56)

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

(57)

dans Hindley-Milner, les types suivants sont toujours accept´es

∀α.α→α

∀α.∀β.α×β→α

∀α.bool×α×α→α

∀α.(α→α)→α

mais plus les types tels que

(∀α.α→α)→(∀α.α→α)

(58)

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

(59)

Γ`x: Γ(x) Γ`n :int...

Γ`+ :int×int→int...

Γ +x:τ1`e :τ2

Γ`funx→e :τ1 →τ2

Γ`e10→τ Γ`e20 Γ`e1 e2

Γ`e11 Γ`e22

Γ`(e1,e2) :τ1×τ2

Γ`e11 Γ +x :σ1 `e22

Γ`letx =e1 in e22 Γ`e :σ α6∈ L(Γ) Γ`e :∀α.σ

(60)

le syst` eme de Hindley-Milner

on note que seule la construction letpermet d’introduire un type polymorphe dans l’environnement

Γ`e11 Γ +x:σ1`e22

Γ`letx=e1 ine22

en particulier, on peut toujours typer

letf =funx →x in (f 1,f true) avec f :∀α.α→α dans le contexte pour typer (f 1,f true)

Jean-Christophe Filliˆatre Langages de programmation et compilation typage 62

(61)

en revanche, la r`egle de typage

Γ +x :τ1 `e :τ2

Γ`funx →e :τ1 →τ2

n’introduit pas un type polymorphe (sinon τ1→τ2 serait mal form´e)

en particulier, on ne peut plus typer

fun x→x x

(62)

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

(63)

nous allons modifier la pr´esentation du syst`eme de Hindley-Milner pour qu’il soit dirig´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

(64)

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

Γ`e10→τ Γ`e20 Γ`e1 e2

Γ`e11 Γ`e22 Γ`(e1,e2) :τ1×τ2

Γ`e11 Γ +x :Gen(τ1,Γ)`e22 Γ`letx =e1 in e22

Jean-Christophe Filliˆatre Langages de programmation et compilation typage 66

(65)

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...αn0 ssi ∃τ1...∃τn. τ =τ01←τ1, ..., αn←τn]

(66)

syst` eme de Hindley-Milner dirig´ e par la syntaxe

• et la g´en´eralisation, dans la r`egle

Γ`e11 Γ +x :Gen(τ1,Γ)`e22 Γ`letx =e1 in e22

o`u

Gen(τ1,Γ) def= ∀α1...∀αn1 o`u {α1, ..., αn}=L(τ1)\L(Γ)

Jean-Christophe Filliˆatre Langages de programmation et compilation typage 68

(67)

α≤α 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

∅ `let f =funx →x in (f 1,f true) :int×bool avec Γ = ∅+f :Gen(α→α,∅)

= f :∀α.α→α

(68)

inf´ erence de types pour mini-ML

pour inf´erer le type d’une expression, il reste des probl`emes

• dans funx→e, quel type donner `ax?

• pour une variable x, 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

(69)

deux id´ees

• on utilise denouvelles variables de types pour repr´esenter les types inconnus

pour le type dex dansfunx 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

(70)

unification

soient deux types τ1 etτ2 contenant des variables de typesα1, . . . , αn existe-t-il une instanciation f 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

(71)

exemple 3 :

τ1 =α→int τ2 =β×γ pas de solution

exemple 4 :

τ1 =α→int τ2

pas de solution

(72)

pseudo-code de l’unification

unifier(τ1, τ2) d´etermine s’il existe une instance des variables de types de τ1 et τ2 telle que τ12

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

(73)

– `ax on donne le typeα1, nouvelle variable de type – la primitive + a le type int×int→int

– typons l’expression (fst x,1)

–fst a pour type le sch´ema ∀α.∀β.α×β →α

– on lui donne donc le type α2×β1 →α2 pour deux nouvelles variables – l’applicationfst x impose d’unifier α1 etα2×β1,⇒ α12×β1 – (fst x,1) a donc le typeα2×int

– l’application +(fst x,1) unifie int×int etα2×int,

(74)

pseudo-code de l’algorithme W

on d´efinit une fonctionW qui prend en arguments un environnement Γ et une expression e et renvoie le type inf´er´e poure

• si e est une variablex,

renvoyer une instance triviale de Γ(x)

• si e est une constantec,

renvoyer une instance triviale de son type (penser `a [] :αlist)

• si e est une primitiveop,

renvoyer une instance triviale de son type

• si e est 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

(75)

soit α une nouvelle variable calculerτ =W(Γ +x:α,e1) renvoyerα →τ

• si e est une applicatione1 e2, calculerτ1=W(Γ,e1) calculerτ2=W(Γ,e2) soit α une nouvelle variable unifier(τ12→α)

renvoyerα

(76)

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

(77)

type tvar = int

type subst = typ TVmap.t

• en utilisant des variables de types destructives

type tvar = { id: int; mutable def: typ option; } il existe ´egalement plusieurs fa¸cons de coder l’algorithme W

• avec des sch´emas explicites et en calculantGen(τ,Γ) type schema = { tvars: TVset.t; typ: typ; }

• avec des niveaux

(78)

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

(79)

comme d´ej`a expliqu´e, on peut d´efinir let recf x =e1 in e2=def

let f =opfix (fun f →funx→e1)in e2

o`u

opfix :∀α.∀β.((α→β)→(α→β))→(α→β) de mani`ere ´equivalente, on peut donner la r`egle

Γ +f :τ →τ1+x:τ `e11 Γ +f :Gen(τ →τ1,Γ)`e22

Γ`let rec f x=e in e :τ

(80)

types construits

on a d´ej`a vu les paires

les listes ne posent pas de difficult´e []: ∀α. α list

::: ∀α. α×α list→α list

Γ`e1 :τ list Γ`e21 Γ +x :τ +y :τ list`e31 Γ`match e1 with []→e2 |::(x,y)→e31

se g´en´eralise ais´ement aux types sommes et produits

Jean-Christophe Filliˆatre Langages de programmation et compilation typage 82

(81)

pour les r´ef´erences, on peut na¨ıvement penser qu’il suffit d’ajouter les primitives

ref: ∀α. α→α ref

!: ∀α. α ref→α

:= : ∀α. α ref→α→unit

(82)

r´ ef´ erences

malheureusement, c’est incorrect !

let r =ref(fun x→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

(83)

pour contourner ce probl`eme, il existe une solution extrˆemement simple,

`

a savoir une restriction syntaxique de la construction let D´efinition (value restriction, Wright 1995)

Un programme satisfait le crit`ere de lavalue restriction si toute sous-expression letest de la forme

letx=v1 ine2

o`u v1 est unevaleur.

(84)

r´ ef´ erences polymorphes

on ne peut plus ´ecrire

letr =ref(funx →x) in . . . mais on peut ´ecrire en revanche

(funr →. . .) (ref(fun x→x)) o`u le type der n’est pas g´en´eralis´e

Jean-Christophe Filliˆatre Langages de programmation et compilation typage 86

(85)

mais le type de r 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

la value 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];;

(86)

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

(87)

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)

(88)

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 de M.create 17?

la r´eponse d´epend du type ’a t : non pour un tableau, oui pour une liste, etc.

en OCaml, une indication devariance permet 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

(89)

deux ouvrages en rapport avec ce cours

• Benjamin C. Pierce, Types and Programming Languages (´egalement en rapport avec le cours 3)

• Xavier Leroy et Pierre Weis, Le langage Caml

(le dernier chapitre explique l’inf´erence avec les niveaux)

(90)

la suite

• TD 7

unification et algorithme W

• prochain cours

mode de passage des param`etres

Jean-Christophe Filliˆatre Langages de programmation et compilation typage 92

Références

Documents relatifs

La programmation, c'est (entre autres) le fait de dialoguer avec l'ordinateur, afin de lui faire faire les opérations que l'on veut : on traduit les opérations dans un langage

Pour justifier compl` etement l’approche d´ ecrite ci-dessus, il faut encore montrer que le syst` eme de type ML monomorphe + la r` egle (let-subst) type exactement les mˆ

ecrivons une fonction add2 qui ajoute une brique de longueur 2 ` a droite d’une rang´ ee de briques r.. il suffit de d´ ecaler les bits 2 fois vers la gauche et d’ajouter

dans ce cours, nous allons effectivement nous int´ eresser ` a la compilation vers de l’assembleur, mais ce n’est qu’un aspect de la compilation un certain nombre de techniques

pour ´ etablir une propri´ et´ e d’une relation d´ efinie par un ensemble de r` egles d’inf´ erence, on peut raisonner par r´ ecurrence sur la d´ erivation. cela signifie par

Jean-Christophe Filliˆ atre Langages de programmation et compilation expressions r´ eguli` eres

par d´ efaut, la priorit´ e d’une production est celle de son lex` eme le plus ` a droite (mais elle peut ˆ etre sp´ ecifi´ ee explicitement).. r´ esolution

en pratique on suppose qu’un symbole terminal # d´ enote la fin de l’entr´ ee, et la table indique donc ´ egalement l’expansion de X lorsque l’on atteint la fin de l’entr´