** 12. Type Inference Formalization ** ---------------------------------------------------------------------------- I'll now formalize the constraint-collection phase of type inference. I'll use the type checking inference rule notation. My judgments will be of the form Gamma |- e : tau => Chi meaning "in the type environment Gamma, expression e is semantically well-formed and produces a value of type tau, as long as the constraints Chi on type variables can be satisfied". In a deterministic algorithm to construct proofs, I'll treat Gamma and e as inputs, and tau and Chi as outputs. (In a real implementation of type inference, I'd continuously update my solution to Chi as I accumulate constraints, taking and returning a substitution on type variables instead of returning a Chi.) Here are the rules for Core ML, where all type declarations are erased. These omitted type declaration are on lambda formals, let bindings, identifier & wildcard pattern bindings, union constructors and patterns, recursive values, and fold expressions. The kinds of constraints inferred are: Chi = set of chi chi ::= tau = tau (* a regular type equality constraint *) | tau = {id:tau',...} (* that a type is a record with an id:tau' case *) | tau = [id:tau',...] (* that a type is a union with an id:tau' case *) | tau = [...] (* that a type is a union *) (The way I thought about how to write each rule was that each judgment "computed" its own result type and constraints on its result type, and the "caller" then added any additional constraints on its "argument" types to compute its result type. Type checking doesn't fail (only identifier references can fail), it just accumulates constraints that may be unsatisfiable.) -------------------- Gamma |- intconst : int => {} -------------------- Gamma |- true : bool => {} -------------------- Gamma |- false : bool => {} Gamma |- e1 : tau1 => Chi1 Gamma |- e2 : tau2 => Chi2 Gamma |- e3 : tau3 => Chi3 -------------------- Gamma |- (if e1 then e2 else e3) : tau2 => Chi1 U Chi2 U Chi3 U { tau1 = bool, tau2 = tau3 } Gamma |- p => Gamma' : tau1 => Chi1 Gamma,Gamma' |- e : tau2 => Chi2 -------------------- Gamma |- (lambda p. e) : tau1->tau2 => Chi1 U Chi2 Gamma |- e1 : tau1 Gamma |- e2 : tau2 -------------------- Gamma |- (e1 e2) : tau => Chi1 U Chi2 U { tau1 = tau2->tau } -------------------- Gamma,id:tau |- id : tau => {} id != id' Gamma |- id : tau => Chi -------------------- Gamma,id':tau' |- id : tau => Chi Gamma |- id : tau => Chi -------------------- Gamma,{} |- id : tau => Chi Gamma |- e1 : tau1 => Chi1 Gamma |- p => Gamma' : tau2 => Chi2 Gamma,Gamma' |- e2 : tau3 => Chi3 -------------------- Gamma |- (let val p = e1 in e2) : tau3 => Chi1 U Chi2 U Chi3 U { tau1 = tau2 } Gamma |- e1 : tau1 => Chi1 ... Gamma |- eN : tauN => ChiN -------------------- Gamma |- {id1=e1, ..., idN=eN} : tau => Chi1 U ... U ChiN U { tau = {id1:tau1, ..., idN:tauN} } Gamma |- e : tau' => Chi' -------------------- Gamma |- (#id e) : tau => Chi' U { tau' = {id:tau,...} } Gamma |- e : tau' => Chi' -------------------- Gamma |- [id=e] : tau => Chi' U { tau = [id:tau',...] } Gamma |- e : tau' => Chi' -------------------- Gamma |- (?id e) : bool => Chi' U { tau' = [id:tau,...] } Gamma |- e : tau' => Chi' -------------------- Gamma |- (%id e) : tau => Chi' U { tau' = [id:tau,...] } Gamma |- e : tau0 => Chi0 Gamma |- p1 => Gamma1 : tau1 => Chi1 Gamma,Gamma1 |- e1 : tau1' => Chi1' ... Gamma |- pN => GammaN : tauN => ChiN Gamma,GammaN |- eN : tauN' => ChiN' -------------------- Gamma |- (case e of p1 => e1 ... pN => eN) : tau => Chi0 U Chi1 U Chi1' U ... U ChiN U ChiN' U { tau0 = tau1 = ... = tauN = [...], tau = tau1' = ... = tauN' } Gamma |- e : tau' => Chi -------------------- Gamma |- (fold e) : tau => Chi U { tau = (rec id = tau''), tau' = tau''[id := tau] } Gamma |- e : tau' => Chi -------------------- Gamma |- (unfold e) : tau => Chi U { tau' = (rec id = tau''), tau = tau''[id := tau'] } Gamma,id:tau |- e : tau' => Chi -------------------- Gamma |- (rec id = e) : tau' => Chi U { tau = tau' } The pattern type inference rules are as follows: -------------------- |- id => ({},id:tau) : tau => {} -------------------- |- (_) => {} : tau => {} |- p1 => Gamma1 : tau1 => Chi1 ... |- pN => GammaN : tauN => ChiN -------------------- |- {id1=p1,...,idN=pN} => (Gamma1,...,GammaN) : {id1:tau1, ..., idN:tauN} => Chi1 U ... U ChiN |- p => Gamma : tau => Chi -------------------- |- [id=p] => Gamma : tau => Chi U { tau = [id:tau,...] }