1 Some abstract interpreters for type inference. 2 Types as abstract interpretations §inspired by a paper of Cousot (POPL ‘97), which l derives several.

Slides:



Advertisements
Similar presentations
1 A B C
Advertisements

Simplifications of Context-Free Grammars
Variations of the Turing Machine
PDAs Accept Context-Free Languages
ALAK ROY. Assistant Professor Dept. of CSE NIT Agartala
AP STUDY SESSION 2.
1
Select from the most commonly used minutes below.
STATISTICS POINT ESTIMATION Professor Ke-Sheng Cheng Department of Bioenvironmental Systems Engineering National Taiwan University.
David Burdett May 11, 2004 Package Binding for WS CDL.
CALENDAR.
1 Program verification: flowchart programs (Book: chapter 7)
Programming Language Concepts
The 5S numbers game..
Break Time Remaining 10:00.
Factoring Quadratics — ax² + bx + c Topic
EE, NCKU Tien-Hao Chang (Darby Chang)
Turing Machines.
PP Test Review Sections 6-1 to 6-6
Modern Programming Languages, 2nd ed.
Outline Minimum Spanning Tree Maximal Flow Algorithm LP formulation 1.
Operating Systems Operating Systems - Winter 2010 Chapter 3 – Input/Output Vrije Universiteit Amsterdam.
How to convert a left linear grammar to a right linear grammar
Copyright © 2012, Elsevier Inc. All rights Reserved. 1 Chapter 7 Modeling Structure with Blocks.
1 Decision Procedures An algorithmic point of view Equality Logic and Uninterpreted Functions.
Chapter 1: Expressions, Equations, & Inequalities
Lilian Blot PART III: ITERATIONS Core Elements Autumn 2012 TPOP 1.
A Third Look At ML 1. Outline More pattern matching Function values and anonymous functions Higher-order functions and currying Predefined higher-order.
Adding Up In Chunks.
MaK_Full ahead loaded 1 Alarm Page Directory (F11)
1 10 pt 15 pt 20 pt 25 pt 5 pt 10 pt 15 pt 20 pt 25 pt 5 pt 10 pt 15 pt 20 pt 25 pt 5 pt 10 pt 15 pt 20 pt 25 pt 5 pt 10 pt 15 pt 20 pt 25 pt 5 pt Synthetic.
Artificial Intelligence
: 3 00.
5 minutes.
1 Non Deterministic Automata. 2 Alphabet = Nondeterministic Finite Accepter (NFA)
1 hi at no doifpi me be go we of at be do go hi if me no of pi we Inorder Traversal Inorder traversal. n Visit the left subtree. n Visit the node. n Visit.
1 Let’s Recapitulate. 2 Regular Languages DFAs NFAs Regular Expressions Regular Grammars.
Types of selection structures
1 Titre de la diapositive SDMO Industries – Training Département MICS KERYS 09- MICS KERYS – WEBSITE.
12 System of Linear Equations Case Study
Converting a Fraction to %
Numerical Analysis 1 EE, NCKU Tien-Hao Chang (Darby Chang)
CSE20 Lecture 15 Karnaugh Maps Professor CK Cheng CSE Dept. UC San Diego 1.
Clock will move after 1 minute
Physics for Scientists & Engineers, 3rd Edition
Lial/Hungerford/Holcomb/Mullins: Mathematics with Applications 11e Finite Mathematics with Applications 11e Copyright ©2015 Pearson Education, Inc. All.
Select a time to count down from the clock above
1 Physics for Scientists and Engineers Chapter 21: The Electric Field I: Discrete Charge Distributions Copyright © 2004 by W. H. Freeman & Company Paul.
Copyright Tim Morris/St Stephen's School
Claus Brabrand, UFPE, Brazil Aug 11, 2010DATA-FLOW ANALYSIS Claus Brabrand ((( ))) Associate Professor, Ph.D. ((( Programming, Logic, and.
1 A simple abstract interpreter to compute Sign s.
1.step PMIT start + initial project data input Concept Concept.
9. Two Functions of Two Random Variables
Impossibility of Consensus in Asynchronous Systems (FLP) Ali Ghodsi – UC Berkeley / KTH alig(at)cs.berkeley.edu.
1 Decidability continued…. 2 Theorem: For a recursively enumerable language it is undecidable to determine whether is finite Proof: We will reduce the.
1 Non Deterministic Automata. 2 Alphabet = Nondeterministic Finite Accepter (NFA)
Distributed Computing 5. Snapshot Shmuel Zaks ©
The Pumping Lemma for CFL’s
4/11/20151 Programming Languages and Compilers (CS 421) Elsa L Gunter 2112 SC, UIUC Based in part on slides by Mattox.
1 Programming Languages (CS 550) Mini Language Interpreter Jeremy R. Johnson.
Chapter 4 FUGACITY.
Type Checking, Inference, & Elaboration CS153: Compilers Greg Morrisett.
1 PROPERTIES OF A TYPE ABSTRACT INTERPRETATER. 2 MOTIVATION OF THE EXPERIMENT § a well understood case l type inference in functional programming à la.
1 How to transform an analyzer into a verifier. 2 OUTLINE OF THE LECTURE a verification technique which combines abstract interpretation and Park’s fixpoint.
1 Basic abstract interpretation theory. 2 The general idea §a semantics l any definition style, from a denotational definition to a detailed interpreter.
Catriel Beeri Pls/Winter 2004/5 type reconstruction 1 Type Reconstruction & Parametric Polymorphism  Introduction  Unification and type reconstruction.
1 How to transform an abstract analyzer into an abstract verifier.
1 Abstract interpretation Giorgio Levi Dipartimento di Informatica, Università di Pisa
Presentation transcript:

1 Some abstract interpreters for type inference

2 Types as abstract interpretations §inspired by a paper of Cousot (POPL ‘97), which l derives several type abstract semantics from a collecting semantics for eager untyped lambda calculus including à la Church/Curry polytypes (with polymorphic recursion and abstraction) l discusses their relation to “more traditional” rule based presentations §most of the abstract semantics are not “effective” l infinite sets of monotypes in the abstract domain l non-effective semantics for lambda abstraction

3 Our experiment §all the abstract interpreters are “effective” type inference algorithms l easy to extend, modify and compare §abstract interpreters rather than abstract semantics l executable specifications of the semantics in ML §principal type inference via Herbrand abstraction l generic and parametric polytypes, represented by (possibly quantified) type expressions with variables (terms) l much in the spirit of ML type inference algorithm

4 The language: syntax §type ide = Id of string §type exp = | Eint of int | Var of ide | Sum of exp * exp | Diff of exp * exp | Ifthenelse of exp * exp * exp | Fun of ide * exp | Rec of ide * exp | Appl of exp * exp | Let of ide * exp * exp | Letrec of ide * exp * exp | Letmutrec of (ide * exp) * (ide *exp) * exp

5 Concrete semantics §denotational interpreter §eager semantics with “run-time” type checking §separation from the main semantic evaluation function of the primitive operations l which will then be replaced by their abstract version §abstraction of concrete values l identity function in the concrete semantics §symbolic “non-deterministic” semantics of the conditional

6 Semantic domains § type proc = eval -> eval and eval = | Funval of proc | Int of int | Wrong let alfa x = x § type env = ide -> eval let emptyenv (x: ide) = alfa(Wrong) let applyenv ((x: env), (y: ide)) = x y let bind ((r:env), (l:ide), (e:eval)) (lu:ide) = if lu = l then e else r(lu)

7 Semantic evaluation function § let rec sem (e:exp) (r:env) = match e with | Eint(n) -> alfa(Int(n)) | Var(i) -> applyenv(r,i) | Sum(a,b) -> plus ( (sem a r), (sem b r)) | Diff(a,b) -> diff ( (sem a r), (sem b r)) | Ifthenelse(a,b,c) -> let a1 = sem a r in (if valid(a1) then sem b r else (if unsatisfiable(a1) then sem c r else merge(a1,sem b r,sem c r))) | Fun(ii,aa) -> makefun(ii,aa,r) | Rec(i,e1) -> makefunrec (i,e1,r) | Appl(a,b) -> applyfun(sem a r, sem b r) | Let(i,e1,e2) -> let d = sem e1 r in if d = alfa(Wrong) then d else sem e2 (bind(r, i,d)) | Letrec(i,e1,e2) -> sem (Let(i,Rec(i,e1),e2)) r | Letmutrec ((i1,e1),(i2,e2),e3) -> sem e3 (makemutrec((i1,e1),(i2,e2),r))

8 Primitive operations 1 let plus (x,y) = match (x,y) with |(Int nx, Int ny) -> Int (nx + ny) | _ -> Wrong let diff (x,y) = match (x,y) with |(Int nx, Int ny) -> Int (nx - ny) | _ -> Wrong let valid x = match x with |Int n -> n=0 let unsatisfiable x = match x with |Int n -> if n=0 then false else true let merge (a,b,c) = match a with |Int n -> if b=c then b else Wrong | _ -> Wrong let applyfun ((x:eval),(y:eval)) = match x with |Funval f -> f y | _ -> Wrong let rec makefun(ii,aa,r) = Funval(function d -> if d = Wrong then Wrong else sem aa (bind(r,ii,d)))

9 Primitive operations 2 let rec funzionale ff i e r = sem e (bind(r,i,ff)) and makefunrec (i,e1,r) = Funval(let rec ff = function d -> if d = Wrong then Wrong else (match funzionale (Funval ff) i e1 r with | Funval f -> f d) in ff) §lfp (funzionale ff i e r) let rec makemutrec ((i1,e1),(i2,e2),r) = let rec ff1 = function d -> if d = Wrong then Wrong else (match sem e1 (bind(bind(r,i1,Funval(ff1)),i2,Funval(ff2))) with Funval f -> f d) and ff2 = function d -> if d = Wrong then Wrong else (match sem e2 (bind(bind(r,i1,Funval(ff1)),i2,Funval(ff2))) with Funval f -> f d) in bind(bind(r,i1,Funval(ff1)),i2,Funval(ff2))

10 Examples 1 §expressions, which have a (type) correct concrete evaluation, and which cannot be typed by the ML type system §f f1 g n x = g(f1 n (x)) # let rec f f1 g n x = if n=0 then g(x) else f(f1) (function x -> (function h -> g(h(x)) )) (n-1) x f1 in f (function x -> x+1) (function x -> -x) 10 5;; This expression has type ('a -> 'a) -> 'b but is here used with type 'b §cannot be typed for the approximation in the abstract fixpoint computation # sem (Letrec (Id "f",Fun(Id "f1", Fun(Id "g", Fun(Id "n", Fun(Id "x", Ifthenelse(Var(Id "n"),Appl(Var(Id "g"),Var(Id "x")), Appl(Appl(Appl(Appl(Appl(Var(Id "f"),Var(Id "f1")), Fun(Id "x",Fun(Id "h", Appl(Var(Id "g"),Appl(Var(Id "h"),Var(Id "x")))))), Diff(Var(Id "n"),Eint 1)),Var(Id "x")),Var(Id "f1"))))))), Appl(Appl(Appl(Appl(Var(Id "f"),Fun(Id "x",Sum(Var(Id "x"),Eint 1))), Fun(Id "x",Var(Id "x"))), Eint 10),Eint 5) ) ) emptyenv;; - : eval = Int 15

11 Examples 2 §expressions, which have a (type) correct concrete evaluation, and which cannot be typed by the ML type system # let rec f x = x and g x = f (1+x) in f f 2;; This expression has type int -> int but is here used with type int §cannot be typed for the approximation in the abstract fixpoint computation (because of mutual recursion) # sem (Letmutrec((Id "f",Fun(Id "x",Var(Id "x"))), (Id "g",Fun(Id "x",Appl(Var(Id "f"),Sum(Eint 1,Var(Id "x"))))), Appl(Appl(Var(Id "f"),Var(Id "f")),Eint 2))) emptyenv;; - : eval = Int 2

12 Examples 3 §expressions, which have a (type) correct concrete evaluation, and which cannot be typed by the ML type system # let rec polyf x y = if x=0 then 0 else if (x-1)=0 then (polyf (x-1)) (function z -> z) else (polyf (x-2)) 0 in polyf 3 1;; This expression has type int but is here used with type ‘a -> ‘a §no polymorphic recursion # sem (Letrec (Id "polyf", Fun(Id "x", Fun (Id "y", Ifthenelse(Var (Id "x"), Eint 0, Ifthenelse (Diff (Var (Id "x"), Eint 1), Appl(Appl (Var (Id "polyf"), Diff (Var (Id "x"), Eint 1)), Fun (Id "z", Var (Id "z"))), Appl (Appl (Var (Id "polyf"), Diff (Var (Id "x"), Eint 2)), Eint 0))))), Appl(Appl(Var (Id "polyf"),Eint 3),Eint 1) )) emptyenv;; - : eval = Int 0

13 Examples 4 §expressions, which have a (type) correct concrete evaluation, and which cannot be typed by the ML type system # (function x -> x x) (function x -> x) 3 This expression has type ‘a -> ‘b but is here used with type ‘a §no polymorphic abstraction # sem (Appl(Appl(Fun(Id "x", Appl(Var(Id "x"),Var(Id "x"))), (Fun(Id "x",Var(Id "x")))), Eint 3) ) emptyenv;; - : eval = Int 3

14 From the concrete to the collecting semantics §the concrete semantic evaluation function l sem: exp -> env -> eval §the collecting semantic evaluation function semc: exp -> env ->  (eval) l semc e r = {sem e r} all the concrete primitive operations have to be lifted to  (eval) in the design of the abstract operations l there exist other (more concrete) collecting semantics semc’: exp ->  (env -> eval)

15 From the collecting to the abstract semantics   concrete domain: (  (ceval),   ) §concrete (non-collecting) environment: l cenv = ide -> ceval   abstract domain: (eval,  ) §abstract environment: env = ide -> eval §the collecting semantic evaluation function semc: exp -> env ->  (ceval) §the abstract semantic evaluation function l sem: exp -> env -> eval

16 Type abstract interpreter 1 §essentially the Hindley monotype abstract interpreter l exact Herbrand abstraction of the Church/Curry monotype semantics l can be made more precise (fixpoint computation) §principal types l monotypes with variables l which subsume all the other types l represented as Herbrand terms terms built on type variables

17 Monotypes with variables §type evalt = Notype | Vvar of string | Intero | Mkarrow of evalt * evalt §the partial order relation (on equivalence classes of terms modulo variance) l anti-instance relation: t 1  t 2, if t 2 is an instance of t 1 Notype is the top element l there exist infinite increasing chains §we look for more general (principal) types l in least fixpoint computations, possible non termination problems

18 Concrete and abstract domains §type evalt = Notype | Vvar of string | Intero | Mkarrow of evalt * evalt  t 1  t 2, if t 2 is an instance of t 1 §lub on evalt: l gci (greatest common instance), computed by unification §glb on evalt: l lcg (least common generalization), computed by anti-unification §even if evalt is not the final abstract domain, we relate it to the concrete domain of the collecting semantics   concrete domain: (  (ceval), , {}, ceval, ,  )  abstract domain: (evalt, , Vvar(_), Notype, lcg, gci)

19 Concretization function   concrete domain: (  (ceval), , {}, ceval, ,  )  abstract domain: (evalt, , Vvar(_), Notype, lcg, gci)   t ( x ) = ceval,if x = Notype { y |  z. y = Int(z)},if x = Intero {}, if x = Vvar(_) {Funval(f) |  d   t (  ) f(d)   t (  )}, if x = Mkarrow( ,  ), ,  ground terms   t (  ), for  ground instance of x, if x = Mkarrow( ,  ),  either  or  non-ground

20 Abstraction function   concrete domain: (  (ceval), , {}, ceval, ,  )  abstract domain: (evalt, , Vvar(_), Notype, lcg, gci)   t ( y ) = gci{ Notype,if Wrong  y Intero, if  z. Int(z)  y Vvar (_), if y = {} lcg{  |  Funval  f)   t (  )}, if Funval(f)  y }   t and  t l are monotonic l define a Galois connection

21 The abstraction of functions l given the concrete (non-collecting) operation let rec makefun(ii,aa,r) = Funval(function d -> if d = Wrong then Wrong else sem aa (bind(r,ii,d))) l in the abstract version one should for each ground type  i –bind d to  i –compute the type  i = sem aa (bind(r,ii,d)) compute the glb of all the resulting functional types: lcg ({Mkarrow(  i,  i )}) l this can be made effective by making a single evaluation, starting from the bottom element l (wrong!) abstract operation let rec makefun(ii,aa,r) = let d = newvar() in let t = sem aa (bind(r,ii,d))) in Mkarrow(d,t)

22 Type variables   t (Vvar(_) ) = {} l a type variable represents the set of all the (concrete) values which have any type, i.e., the empty set §(fresh) type variables are introduced in the abstract version of makefun l (wrong!) abstract operation let rec makefun(ii,aa,r) = let d = newvar() in let t = sem aa (bind(r,ii,d))) in Mkarrow(d,t) §the problem l the evaluation of the function body should (possibly) lead to an instantiation of d

23 Towards constraints §(wrong!) abstract operation let rec makefun(ii,aa,r) = let d = newvar() in let t = sem aa (bind(r,ii,d))) in Mkarrow(d,t) §Fun(Id “x”, Sum(Var(Id “x”), Eint 1)) l “x” is bound to a new variable Vvar “0” in the environment r l the expression Sum(Var(Id “x”), Eint 1)) is evaluated in r l the abstract Sum operation needs to instantiate the type variable Vvar “0” to Intero abstraction of the concrete type checking §this can be achieved l by forcing abstract operations to return an abstract value and an abstract environment changing the structure of the concrete semantic evaluation function l by extending the abstract domain to pairs consisting of a term (type) and a constraint on type variables

24 The real abstract domain §type evalt = Notype | Vvar of string | Intero | Mkarrow of evalt * evalt type eval = evalt * (evalt * evalt) list §the second component of an abstract value (the constraint) represents a set of term equalities (equations) §each abstract operation l combines the constraints in the arguments and updates the result with new constraints l checks the resulting constraint for satisfiability and transforms it to solved form (by means of unification) l applies the constraint in solved form (substitution) to the type l returns the pair (type,constraint) §the partial order on eval and the corresponding lub and glb operations are obtained by lifting the definitions for evalt

25 Two abstract operations let plus ((v1,c1),(v2,c2)) = let sigma = unifylist((v1,Intero) :: (v2,Intero) :: c2)) in match sigma with |Fail -> (Notype,[]) |Subst(s) -> (Intero,s) let rec makefun(ii,aa,r) = let f1 =newvar() in let f2 =newvar() in let body = sem aa (bind(r,ii,(f1,[]))) in (match body with (t,c) -> let sigma = unifylist( (t,f2) :: c) in (match sigma with |Fail -> (Notype,[]) |Subst(s) -> ((applysubst sigma (Mkarrow(f1,f2))),s)))

26 Merge and function application let gci ((v1,c1),(v2,c2)) = let sigma = unifylist((v1,v2) :: c2)) in match sigma with |Fail -> (Notype,[]) |Subst(s) -> (applysubst sigma v1,s) let merge (a,b,c) = match a with |(Notype,_) -> (Notype,[]) |(v0,c0) -> let sigma = unifylist((v0,Intero)::c0) in match sigma with |Fail -> (Notype,[]) |Subst(s) -> match gci(b, c) with |(Notype,_) -> (Notype,[]) |(v1,c1) -> let sigma1 = in match sigma1 with |Fail -> (Notype,[]) |Subst(s1) -> (applysubst sigma1 v1,s1) letapplyfun ((v1,c1),(v2,c2)) = let f1 =newvar() in let f2 =newvar() in let sigma = unifylist((v1,Mkarrow(f1,f2)) :: (v2,f1) :: c2)) in match sigma with |Fail -> (Notype,[]) |Subst(s) -> (applysubst sigma f2,s)

27 Abstract least fixpoint computation let makefunrec (i, e1, r) = alfp ((newvar(),[]), i, e1, r ) let rec alfp (ff, i, e1, r ) = let tnext = funzionale ff i e1 r in (match tnext with |(Notype, _) -> (Notype,[]) |_ -> if abstreq(tnext,ff) then ff else alfp(tnext, i, e1, r ) ) ) §because of infinite increasing chains, the fixpoint computation may diverge (an example later) l we need a widening operator computing an upper approximation of the lfp

28 Abstract least fixpoint computation let makefunrec (i, e1, r) = alfp ((newvar(),[]), i, e1, r, k) let rec alfp (ff, i, e1, r, n) = let tnext = funzionale ff i e1 r in (match tnext with |(Notype, _) -> (Notype,[]) |_ -> if abstreq(tnext,ff) then ff else (if n = 0 then widening(ff,tnext) else alfp(tnext, i, e1, r, n-1) ) ) let widening ((f1,c1),(t,c)) = let sigma = unifylist( (t,f1) :: in (match sigma with |Fail -> (Notype,[]) |Subst(s) -> (applysubst sigma t,s))

29 Mutual recursion let makemutrec ((i1,i2), (e1,e2), r) = let (v1,v2) = alfpm ((newvar(),[]),(newvar(),[]) ((i1,i2), (e1,e2), r, k) in bind(bind(r,i1,v1),i2,v2) let rec alfpm ((ff1,ff2), ((i1,i2), (e1,e2), r, n) = let r1 = bind(bind(r,i1,ff1),i2,ff2) in let tnext1 = sem e1 r1 in let tnext2 = sem e2 r1 in (match (tnext1, tnext2) with |((Notype, _), _) -> (Notype,[]), (Notype,[]) |(_,(Notype, _)) -> (Notype,[]), (Notype,[]) |_ -> if abstreq(tnext1,ff1) & abstreq(tnext2,ff2) ) then (ff1,ff2) else (if n = 0 then widening(ff1, ff2, tnext1, tnext2) else alfpm((tnext1,tnext2), ((i1,i2), (e1,e2), r, n-1) ) ) §with the straightforward extension of widening

30 Abstract least fixpoint computation §both Hindley’s and ML’s type inference algorithms do not try to compute the fixpoint and simply perform the widening (unification) at step 1 §abstreq checks the two terms in the abstract values for variance §the abstract semantic evaluation function is left unchanged l we just add an external function which sets the widening parameter k let sem1 (e:exp) (k:int) = ……… in sem e emptyenv

31 Examples 1: non-termination # let rec f x = f in f;; This expression has type 'a -> 'b but is here used with type 'b # sem1 (Rec(Id "f",Fun(Id "x",Var(Id "f")))) 0;; - : eval = Notype, [] # sem1 (Rec(Id "f",Fun(Id "x",Var(Id "f")))) 5;; - : eval = Notype, [] # sem1 (Rec(Id "f",Fun(Id "x",Var(Id "f")))) (-1);; Interrupted.

32 2: “easy” recursion # let fact = Rec ( Id("pfact"), Fun(Id("x"), Ifthenelse(Diff(Var(Id("x")),Eint(1)), Eint(1), Sum(Var(Id("x")), Appl(Var(Id("pfact")),Diff(Var(Id("x")),Eint(1))))))) ….. # sem1 fact 0;; - : eval = Mkarrow (Intero, Intero),[…] # sem1 fact (-1);; - : eval = Mkarrow (Intero, Intero),[…]

33 3: non-typable Cousot’s function # let rec f f1 g n x = if n=0 then g(x) else f(f1)(function x -> (function h -> g(h(x)))) (n-1) x f1;; This expression has type ('a -> 'a) -> 'b but is here used with type 'b # let monster = Rec (Id "f",Fun(Id "f1", Fun(Id "g", Fun(Id "n", Fun(Id "x", Ifthenelse(Var(Id "n"),Appl(Var(Id "g"),Var(Id "x")), Appl(Appl(Appl(Appl(Appl(Var(Id "f"),Var(Id "f1")), Fun(Id "x",Fun(Id "h", Appl(Var(Id "g"),Appl(Var(Id "h"),Var(Id "x")))))),Diff(Var(Id "n"),Eint 1)),Var(Id "x")),Var(Id "f1"))))))));; …... # sem1 monster 2;; - : eval = Mkarrow (Mkarrow (Vvar "var43", Vvar "var43"), Mkarrow (Mkarrow (Vvar "var43", Vvar "var36"), Mkarrow (Intero, Mkarrow (Vvar "var43", Vvar "var36")))), [...] §same result for k=-1 (lfp) # sem1 monster 0;; - : eval = Notype, [] # sem1 monster 1;; - : eval = Notype, []

34 3: failure in widening (Vvar "var0", [])(initial approximation) (Mkarrow(Vvar "var17", Mkarrow(Mkarrow (Vvar "var15", Vvar "var8"), Mkarrow (Intero, Mkarrow (Vvar "var15", Vvar "var8")))), [.…; Vvar "var0", Mkarrow (Vvar "var17", Mkarrow(Mkarrow (Vvar "var13", Mkarrow (Mkarrow (Vvar "var13", Vvar "var15"), Vvar "var8")), Mkarrow(Intero, Mkarrow (Vvar "var15", Mkarrow (Vvar "var17", Vvar "var8"))))) ; ]) (Mkarrow (Mkarrow (Vvar "var43", Vvar "var43"),Mkarrow (Mkarrow (Vvar "var43", Vvar "var36"), Mkarrow (Intero, Mkarrow (Vvar "var43", Vvar "var36")))), [...…; Vvar "var8", Mkarrow (Mkarrow (Vvar "var43", Vvar "var43"), Vvar "var36");...]) (Mkarrow (Mkarrow (Vvar "var43", Vvar "var43"), Mkarrow (Mkarrow (Vvar "var43", Vvar "var36"), Mkarrow (Intero, Mkarrow (Vvar "var43", Vvar "var36")))), [...])

35 4: successful widening loses precision # let f1 x = x in let g x = f1 (1+x) in f1;; - : 'a -> 'a = # let rec f x = x and g x = f (1+x) in f;; - : int -> int = # let f1 = Let(Id "f",Fun(Id "x",Var(Id "x")), Let(Id "g",Fun(Id "x",Appl(Var(Id "f"),Sum(Eint 1,Var(Id "x")))), Var(Id "f")));; …. # sem1 f1 (-1);; - : eval = Mkarrow (Vvar "var1", Vvar "var1"), […..] # let f = Letmutrec((Id "f",Fun(Id "x",Var(Id "x"))), (Id "g",Fun(Id "x",Appl(Var(Id "f"),Sum(Eint 1,Var(Id "x"))))), Var(Id "f"));; …. # sem1 f (-1);; - : eval = Mkarrow (Vvar "var9", Vvar "var9"), […..] # sem1 f 0;; - : eval = Mkarrow (Intero, Intero), […...]

36 5: no let-polymorphism # let f x = x in f f;; - : '_a -> '_a = # sem1 (Let(Id "f",Fun(Id "x", Var(Id "x")),Appl(Var(Id "f"),Var(Id "f")))) 0;; - : eval = Notype, []

37 Polymorphism 1  evaluation of an expression e in an environment containing an association between an identifier n and a type  l Let(i,e1,e2)evaluation of e2 with a new association for i l Rec(f,e) evaluation of e with a new association for f (function name) l Fun(x,e) evaluation of e with a new association for x (parameter)  if  contains (type) variables, different occurrences of n in e can use different instances of  §let-polymorphism l applies only to associations created by Let §polymorphic recursion l applies to recursive calls of f in e §polymorphic abstraction l applies to the occurrences of the formal parameter x in e

38 Polymorphism 2 §ML provides let polymorphism only l similar to our second abstract interpreter §our third interpreter will handle polymorphic recursion as well §polymorphic abstraction cannot easily be handled within our approach l Herbrand abstraction and principal types §it can be handled using sets of types as abstract domain l see Cousot’s paper l abstract semantics rather than effective abstract interpreter

39 Towards polymorphism §the basic mechanism to allow polymorphism is to represent types as universally quantified (closed) terms l whenever the environment is applied to an identifier it returns a renamed version of the type (using fresh variables) §unfortunately, types are not closed terms l they are in general open terms, in which some variables (free variables) cannot be renamed §free variables can be determined from the current environment l they are exactly those variables which occur in the environment §all the remaining variables are bound and therefore explicitely universally quantified

40 Parametric polytypes 1 type evalt = Notype | Vvar of string | Intero | Mkarrow of evalt * evalt type tscheme = Forall of (string list) * evalt type eval = tscheme * (evalt * evalt) list §the new operations l val instance: eval -> eval returns a new abstract value, whose tscheme is the most general instance of the input one –a renaming with fresh variables replacing universally quantified variables l val generalize : evalt -> subst -> env -> tscheme generalizes the input type by returning a tscheme in which all the variables which do not occur in the current environment determined by the environment and the current substitution are universally quantified

41 Parametric polytypes 2 type evalt = Notype | Vvar of string | Intero | Mkarrow of evalt * evalt type tscheme = Forall of (string list) * evalt type eval = tscheme * (evalt * evalt) list §the new environment l to make easier the application of substitution type env = (ide * eval) list let emptyenv = [] let rec bind ((r:env),i,t) = match r with | [] -> [(i,t)] | (j,t1):: r1 -> if i=j then (i,t):: r1 else (j,t1):: (bind(r1,i,t)) let rec applyenv ((r:env),i) = match r with |[] -> (Forall([],Notype),[]) |(j,t):: r1 -> if i=j then instance(t) else applyenv(r1,i)

42 Type abstract interpreter 2 §partial order, glb and lub on the new abstract domain are similar to the previous ones §we might have used the same domain in the monotype interpreter l without taking instances in applyenv l abstreq could (correctly) check variance of universally quantified variables only §the new abstract operations are the straightforward adaptation of the previous ones l quantification prefixes are ignored l computed type schemes have usually an empty list of quantified variables

43 Some abstract operations let plus ((Forall(_,v1),c1),(Forall(_,v2),c2)) = let sigma = unifylist((v1,Intero) :: (v2,Intero) :: c2)) in match sigma with |Fail -> (Forall([],Notype),[]) |Subst(s) -> (Forall([],Intero),s) let rec makefun (ii,aa,r) = let f1 =newvar() in let f2 =newvar() in let body = sem aa (bind(r,ii,(Forall([],f1),[]))) in (match body with | (Forall(_,t),c) -> let sigma = unifylist( (t,f2) :: c) in (match sigma with |Fail -> (Forall([],Notype),[]) |Subst(s) -> (Forall([],applysubst sigma (Mkarrow(f1,f2))),s)))

44 Let-polymorphism §we only use type generalization in the semantics of the let construct let rec sem (e:exp) (r:env) = match e with …. | Let(i,e1,e2) -> let (s,c) = sem e1 r in match s with |Forall(_,Notype) -> (Forall([],Notype),[]) |Forall(_,t) -> let t1 = generalize t (Subst c) r in sem e2 (bind (r, i, (t1,c)))

45 Typings §type systems specified by inference rules do usually infer for a given expression a typing a pair ( ,r)  is a (non-quantified) type expression r is an environment §this allows one to assign a typing to open lambda- expressions containing references to global names l the result gives us constraints on the global environment §our type interpreter 2 has been modified so as to return a typing l the “external function” sem1 takes an additional argument the list of global names

46 Examples 1 # let f x = x in f f;; - : '_a -> '_a = # sem1 (Let(Id "f",Fun(Id "x", Var(Id "x")),Appl(Var(Id "f"),Var(Id "f")))) [] 0;; - : evalt * (string * evalt) list = Mkarrow (Vvar "var2", Vvar "var2"), [] # let f x y = x in f (f 2 3)(f 3 (f 2 ));; - : int = 2 # sem1 (Let(Id "f", Fun (Id "x",Fun(Id "y",Var(Id "x"))), Appl(Appl(Var(Id "f"), Appl(Appl(Var(Id "f"),Eint 2),Eint 3)), Appl(Appl(Var(Id "f"),Eint 3), Appl(Var(Id "f"), Eint 2))))) [] 0;; - : evalt * (string * evalt) list = Intero, []

47 Examples 2 §no news for the monster function l as expected, since it does not contain any Let # sem1 monster [] 0;; - : evalt * (string * evalt) list = Notype, [] # sem1 monster [] 1;; - : evalt * (string * evalt) list = Notype, [] # sem1 monster [] 2;; - : evalt * (string * evalt) list = Mkarrow(Mkarrow (Vvar "var43", Vvar "var43"), Mkarrow(Mkarrow (Vvar "var43", Vvar "var36"), Mkarrow(Intero, Mkarrow (Vvar "var43", Vvar "var36")))), []

48 Examples 3 §inferring typings for “open” expressions l not typable in ML # sem1(Appl(Fun(Id "x", Appl(Var(Id "x"),Var(Id "y"))), Fun (Id "x", Var(Id "x")))) ["y"] 0;; - : evalt * (string * evalt) list = Vvar "var9", ["y", Vvar "var9"] # sem1(Rec(Id "times", Fun(Id "x", Fun (Id "y", Ifthenelse(Var(Id "x"), Var(Id "z"), Sum(Var(Id "y"),Appl(Appl(Var(Id "times"), Diff(Var(Id "x"),Eint 1)),Var(Id "y")))))))) ["z"] 0;; - : evalt * (string * evalt) list = Mkarrow (Intero, Mkarrow (Intero, Intero)), ["z", Intero]

49 Examples 4 §still no polymorphic recursion # let rec polyf x y = if x=0 then 0 else if (x-1)=0 then (polyf (x-1)) (function z -> z) else (polyf (x-2)) 0;; This expression has type int but is here used with type 'a -> 'a # sem1(Rec (Id "polyf", Fun (Id "x", Fun (Id "y", Ifthenelse (Var (Id "x"), Eint 0, Ifthenelse ( Diff (Var (Id "x"), Eint 1), Appl (Appl (Var (Id "polyf"), Diff (Var (Id "x"), Eint 1)), Fun (Id "z", Var (Id "z"))), Appl(Appl (Var (Id "polyf"), Diff (Var (Id "x"), Eint 2)), Eint 0))))))) [] (-1);; - : evalt * (string * evalt) list = Notype, []

50 Type abstract interpreter 3 §polymorphic recursion §same abstract domain of interpreter 2 §the essential feature l the abstract values denoted by the recursive function name within the fixpoint computation need to be generalized and therefore correctly universally quantified so as to allow different instantiations in each iteration of the evaluation of the function body §we have decided to generalize all the computed type schemes l universally quantified types in the result l no special handling of Let l fresh variables used in the semantic of functional abstraction are still free variables

51 Abstract semantics of recursive functions let rec makefunrec (i,e1,r) = let f1 =newvar() in (match f1 with Vvar(x) -> alfp((Forall([x],f1),[]), i, e1, r, k)) and alfp (ff,i,e1,r, n) = let tnext = sem e1 (bind(r,i,ff)) in (match tnext with |(Forall(_,Notype),_) -> (Forall([],Notype),[]) |(Forall(_,t),c) -> let t1 = generalize t (Subst c) r in if abstreq((t1,c),ff) then ff else (if n = 0 then widening(ff,(t1,c),r) else alfp ((t1,c),i,e1,r, n-1) ) l note that the Ml widening (k=0) would always succeed computing an incorrect type

52 Generalizations §generalization is performed before returning the abstract value in l merge l applyfun l widening l makefun let rec makefun (ii,aa,r) = let f1 =newvar() in let f2 =newvar() in let body = sem aa (bind(r,ii,(Forall([],f1),[]))) in (match body with | (Forall(_,t),c) -> let sigma = unifylist( (t,f2) :: c) in (match sigma with |Fail -> (Forall([],Notype),[]) |Subst(s) -> let t1 = applysubst sigma (Mkarrow(f1,f2)) in (generalize t1 sigma r,s))) §generalization is removed from the semantics of Let l becomes the same of interpreter 1

53 Examples 1 §let polymorphism still ok without ad-hoc semantics # sem1 (Let(Id "f",Fun(Id "x", Var(Id "x")),Appl(Var(Id "f"),Var(Id "f")))) 0;; - : eval = Forall (["var2"], Mkarrow (Vvar "var2", Vvar "var2")), [...] §polymorphic recursion # let rec polyf x y = if x=0 then 0 else if (x-1)=0 then (polyf (x-1)) (function z -> z) else (polyf (x-2)) 0;; # sem1(Rec (Id "polyf", Fun (Id "x", Fun (Id "y", Ifthenelse (Var (Id "x"), Eint 0, Ifthenelse (Diff (Var (Id "x"), Eint 1), Appl (Appl (Var (Id "polyf"), Diff (Var (Id "x"), Eint 1)), Fun (Id "z", Var (Id "z"))), Appl(Appl (Var (Id "polyf"), Diff (Var (Id "x"), Eint 2)), Eint 0))))))) [] (-1);; - : eval = Forall (["var3"], Mkarrow (Intero, Mkarrow (Vvar "var3", Intero))), [...]

54 Examples 2 §improvement in the fixpoint computation (more precise widening) # sem1 monster 1;; - : eval = Forall (["var15"; "var8"], Mkarrow(Mkarrow (Vvar "var15", Vvar "var15"), Mkarrow(Mkarrow (Vvar "var15", Vvar "var8"), Mkarrow (Intero, Mkarrow (Vvar "var15", Vvar "var8"))))), [...]

55 No polymorphic abstraction # (function x -> x x) (function x -> x) This expression has type 'a -> 'b but is here used with type 'a # let x = function x -> x in x x - : '_a -> '_a = # sem1 (Appl(Fun(Id "x", Appl(Var(Id "x"),Var(Id "x"))),(Fun(Id "x",Var(Id "x")))) ) 0;; - : eval = Forall ([], Notype), [] # sem1 (Let(Id "x",Fun(Id "x",Var(Id "x")),Appl(Var(Id "x"),Var(Id "x"))) ) 0;; - : eval = Forall (["var2"], Mkarrow (Vvar "var2", Vvar "var2")), [...] §universally quantifying the variable bound to the formal parameter in the lambda abstraction does not work §with polymorphic abstraction the semantics of the following constructs should be equivalent (no need for let) §let x = e1 in e2 and (function x -> e2) e1 §this is not the case as shown by the following example

56 Relation to type systems §we will look at some of the rules corresponding to the let polymorphic abstract semantics with 0-widening l ML and Damas-Milner’s semantics §traditional type systems are specified by providing l a notion of type type assertions of the form: expression  type Eint(x)   Intero a notion of judgment of the form: environment   assertion the environment entails the assertion r   Eint(x)   Intero l a set of type rules which assert the validity of certain judgments on the basis of other judgments r   Eint(x)   Intero r   e1   Intero r   e2   Intero r   Sum(e1,e2)   Intero

57 The Damas-Milner’s type system §types l terms with type variables, generalized in the environment when created by the let construct §some rules r   Eint(x)   Intero   elim(applyenv(r,i)) r   Var(x)    r   e1   Intero r   e2   Intero r   Sum(e1,e2)   Intero r[x   1 ]   e    r   Fun(x,e)   Mkarrow(  1,  2 ) r[f  Mkarrow(  1,  2 )]   Fun(x,e)   Mkarrow(  1,  2 ) r   Rec(f,x,e)   Mkarrow(  1,  2 )

58 The Damas-Milner’s type system 2 r   e1   Intero r   e2   Intero r   Sum(e1,e2)   Intero ok for type checking for type inference, judgments have to be understood as going from expressions to pairs (environment,type), i.e. –we need to compute an environment making the judgment valid –the algorithm is not straightforward r[x   1 ]   e    r   Fun(x,e)   Mkarrow(  1,  2 ) r[f  Mkarrow(  1,  2 )]   Fun(x,e)   Mkarrow(  1,  2 ) r   Rec(f,x,e)   Mkarrow(  1,  2 ) even worse: no hints on how to choose  1 and on how to solve the recursive definition

59 Type systems vs. abstract interpreters §for a given a notion of type l a type system is easier to specify it may be quite complex to move from the rules to the type inference algorithm needs some way of relating it to the semantics, to show the correctness (for example subject reduction) l an abstract interpreter may require an abstract domain more complex than just the type is directly a type inference algorithm is correct by construction