Вы находитесь на странице: 1из 57
INFORMATION AND COMPUTATION TIS, 38-94 (1994) A Syntactic Approach to Type Soundness AnpreW K. WRIGHT AND MATTHIAS FELLEISEN* Department of Computer Science, Rice University, Houston, Texas 77251-1892 We present a new approach to proving type soundness for Hindley/Milner-style polymorphic type systems. The keys to our approach are (1) an adaptation of subject reduction theorems from combinatory logic to programming languages, and (2) the use of rewriting techniques for the specification of the language semantics, The approach easily extends from polymorphic functional languages to imperative languages that provide references, exceptions, continuations, and similar features. We illustrate the technique with a type soundness theorem for the core of STANDARD ML, which includes the first type soundness proof for polymorphic exceptions and continuations. + 194 Academie Press. tne. 1. Typr SOUNDNESS Static type systems for programming languages attempt to prevent the occurrence of type errors during execution. A definition of type error depends on a specific language and type system, but always includes the use of a function on arguments for which it is not defined, and the attempted application of a non-function. A static type system is sound if well-typed programs cannot cause type errors; a programming language with a sound static type system is strongly typed [7]. While it is easy to design a sound type system for an explicitly typed monomorphic language, the formulation of a sound type system for a language based on Hindley/Milner-style polymorphism and type inference is delicate [6, 8, 15, 17, 20, 37]. Although the treatment of purely func- tional languages is relatively well understood in this framework, the incorporation of imperative features such as references and exceptions requires extreme care, and the soundness of such systems is not obvious. A formal proof of soundness is required to lend credibility to the claim that such a system prevents type errors, and may be a crucial tool in the design of the type system. * This research was supported in part by the United States Department of Defense under a National Defense Science and Engineering Graduate Fellowship, and by NSF Grant CCR 89-1702. 38 (0890-5401/94 $6.00 Copyright 1994 by Academic Pres. {ne All rights of reprodvetion in an) form reserved, SYNTACTIC TYPE SOUNDNESS 39 We view a static type system for an implicitly typed language as a filter that selects well-typed programs from a larger universe of untyped programs. A partial function eval: Programs Answers U {WRONG} defines the semantics of untyped programs. The result wRoNG is returned for programs whose evaluation causes a type error; eval is undefined for programs whose evaluation does not terminate. Let >e:t mean that the type system assigns program e the type t, ie, e is well-typed. The simplest soundness property states that well-typed programs do not yield wRonc [20]. Derinition (Weak Soundness). If > e: 1 then eval(e) # WRONG. While weak soundness establishes that a static type system achieves its primary goal of preventing type errors, it is often possible to demonstrate a stronger property that relates the answer produced to the type of the program. If we view each type t as denoting different subsets V* of the set of all answers V, then strong soundness states that an answer v produced by a terminating program of type t is an element of the subset V". Derinrmion (Strong Soundness). If =e: + and eval(e)= then ve V*. Strong soundness permits an implementation of the language to associate the representation of a value with its type, and thereby omit the representation tags required by dynamically typed languages. Weak sound- ness follows from strong soundness since WRONG is not a member of V" for any type t. Significant effort has been invested in proving type soundness for Hindley/Milner-style type systems, and their practical realization in the programming language STANDARD ML [22, 23]. Soundness proofs exist for the functional fragment [20,36], for extensions including references (6, 17, 35,37], and for a monomorphic language including first-class continuations [8]. However, there are several drawbacks to the existing proofs. Proofs of type soundness are sensitive to the precise formulation of the semantics of the language—different techniques are required for denotational versus operational formulations of the semantics, and even for different languages within the same semantic framework. The proofs for two different languages are difficult to reconcile to prove soundness for a language including features of both. The existing techniques are complicated, and the resulting proofs are lengthy and error-prone. For an illustration of the difficulties with such proofs, we refer the reader to Tofie’s [37] discussion of Dama’s [6] faulty proof of a type soundness theorem for a polymorphic language with references. We present a simple approach to the proof of soundness for Hindley/Milner-style polymorphic type systems. Our approach is based on 40 WRIGHT AND FELL subject reduction, a classical result from combinatory logic [4], and on rewriting as a means of specifying operational semantics [11-14]. To demonstrate the approach, we develop a proof of soundness for the core! of STANDARD ML, which extends a functional polymorphic language with references and exceptions. We also show soundness for an extension to STANDARD ML with first-class continuations. In principle, our approach is uniformly applicable to any language; in practice, the resulting proofs are lengthy but simple, requiring only ordinary inductive techniques. In the next section, we describe a prototypical functional language with a polymorphic type system, and discuss the various approaches that have previously been used to prove type soundness. Section 3 presents the essence of our approach to proving type soundness; the remaining sections develop illustrative proofs of type soundness for a specific functional language and various extensions, 2. PREVIOUS APPROACHES TO PROVING TyPE SOUNDNESS Any proof of type soundness is intimately tied to the formulation of the semantics of the language. The earlier proofs relied on denotational seman- tics; later proofs used structural operational semantics. The following two subsections briefly present these approaches from a historical perspective. The third subsection discusses the problems with them. We begin with a brief introduction to the formulation of Hindley/Milner-style type systems, in order to introduce our notation. Our prototypical functional language has the (abstract) syntax esse |x} Axe |eye2| let x bee, ines, where xe Var and ce Const. Constants (Const) include both data (integer, real, boolean, etc.) and operations (+, +, A, Vv, etc.). Variables (Var) are lexically scoped. Juxtaposition denotes application and is left associative; J-expressions construct call-by-value procedural abstractions, Semanti- cally the let-expression behaves like ((4x.e2) ¢,), binding the value of e, to x in e,; however, the type system allows x to be polymorphic: different occurrences of x in e, may be assigned different types. A polymorphic type system for this language has types of the form rr where 1,,...1, are ground types like inr and bool. The type system is formulated as a deductive proof system that assigns types to expressions. Mitchell and Harper refer to the functional polymorphic sublanguage as the essence of ML [24]. However, the difficulties of typing references and exceptions [6, 17, 35, 37] and the fact that they cannot be expressed by facilities of the functional core [10] indicate that they are equally important. SYNTACTIC TYPE SOUNDNESS 41 The proof system produces conclusions, or type judgments, of the form oe: , meaning that expression e has type t in type environment F. Type environments are finite maps from variables to types, and are used to give types to open expressions. The typing rules are fex:t if Most (var) Foee:t if TypeOf(c)= (const) Txeujee:tn (abs) Te dxe:ty >t Peeint Perit ena (app) > 18) 5% fee: Coelxere]:ty Te letx bee, ine;:t ‘The function TypeOf assigns types to constants. /[x++z] denotes the functional extension or update of map I’ at x to t; e[x+e"] means the capture-avoiding substitution of e’ for x in e. Programs are closed expressions. A program e is well-typed if it has a type t in the empty type environment; we then write & e : t. 2.1. Proofs Based on Denotational Semantics Milner [20]. Milner formulated and proved a type soundness theorem for a functional language like the above based on a denotational semantics for the language of untyped expressions, The semantic domain is the solution of the following reflexive domain equation [32]: V=B8)0...08,0FOW FaVsV. Bp, ..., B, are basic domains (with bottom), such as integers and booleans; F is the function domain; W is a domain consisting of the single element WRONG; @ is the separated sum; and ~> builds continuous functions. The meaning function & is constructed so as to assign the denotation WRONG to programs that result in type errors. To assign meanings to expressions with free variables, the meaning function takes an environment p: Var 0+ V, a finite map from variables to denotational values. To establish soundness, Milner introduced a semantic relation —. This relation identifies each type t with an ideal V‘ of the domain V [18]. An ideal is simply a subset of the domain that is closed under certain opera- tions (subset and least upper bounds of finite consistent subsets); each of 42 WRIGHT AND FELLEISEN the basic domains forms an ideal. A denotational value ve V possesses type t, written | v:t, if v is a member of the ideal corresponding to t; ie., veV' if fort. An environment p respects a type environment I, written p:/, if the domain of p is at least as large as the domain of I, and for every variable x in the domain of FF p(x): F(x). A semantic soundness theorem states that if an expression ¢ has type t in type environment F, and if environment p respects F’, then the denotation of e in p possesses type t. THEOREM (Semantic Soundness). If [ee:t and fp: then F élelp :c. This theorem is proved by induction on the structure of e. Strong sound- ness follows by restricting the theorem to closed expressions. TueoREM (Strong Soundness). If oe :t then 6[e] Bt. Weak soundness is a consequence of the fact that WRONG does not possess any type. TueoRem (Weak Soundness). If =e: 1 then lle] @ # WRONG. Damas [5,6]. Damas extended Milner’s results to a language with reference cells and destructive assignment. The proof technique is derived from Milner’s technique; however, the proof is significantly more complicated. The denotational semantics uses the domain construction V=B,®...©B, @FOLOW F=V+S>V@S s=v* L=N,, where the domain of locations L is the flat domain of natural numbers, S is the domain of stores (sequences of values), and @ is the smash product. Procedures take both an input value and a store, and produce a result and a new store. The meaning function is parameterized over both a store and an environment. Due to the presence of stores, types are no longer ideals in V, but are finite maps from store typings to subsets of V.? A store typing is a finite map from locations to the types of values stored there. Since the ? This is an over-simplicifation; the reader interested in the precise definition is referred to Damas’s thesis [6]. SYNTACTIC TYPE SOUNDNESS 43 semantic relation (~) must involve the types of values in the store, it can no longer be defined by induction on types; its existence must be estab- lished by a category theoretical argument that generalizes the technique of inclusive predicates [31]. The complexity of the semantic relation complicates the proof; indeed, Tofte found a mistake in Damas’s proof, although the theorem is not thought to be false [37, p. 2]. Abadi et al. [1]. Abadi er al. demonstrate type soundness for a func- tional language with a dynamic type and related operations. Their proof with respect to a denotational semantics is similar to Milner’s proof, although it is complicated by the presence of dynamic values. A dynamic value is a pair consisting of a valuev and a tag, drawn from a set TypeCode, that encodes the type of v. The domain equation includes a domain of dynamic values D: V=8,®...©8, OFODOW FaVoV D = TypeCode x V As type codes correspond to types, the denotation of a type code is a type. Types, in turn, denote ideals over V, but due to the unusual element D of the domain equation, establishing that types denote ideals requires extending the ideal model for recursive types [18]. The proof that the required fixed points exist in the new model involves a metric space argu- ment, but is a straightforward extension of the original. Although the type system Abadi et al. use is not polymorphic, it should be possible to extend the type system and the soundness proof to include polymorphism. Duba et al, [8]. Dubaet al, present several languages extending a monomorphic functional core with first-class continuations in the spirit of Scheme [28]. They describe several approaches to proving type soundness for the languages. One is with respect to a continuation-passing denota- tional semantics, based on the domain equations V=6)@...©8, OFOK FaV>KSA K=VA A=Vew, where IK is the domain of continuations, and A is the domain of answers. The meaning function & takes both an environment and a continuation. Two semantic relations state what is means for a value v to possess a type t, written — v:t, and for a continuation x to accept a value of type t, oats 44 WRIGHT AND FELLEISEN written | x ::t. These relations are defined simultaneously by induction on types. The semantic soundness theorem states that if an expression e has type t in type environment F, and if p respects I, and if continuation x accepts values of type t, then the meaning of ¢ in environment p and continuation k is not WRONG. TueoreM (Semantic Soundness). If Poe: t and — p:T and est then &[e] pk # WRONG. Unlike in the purely functional setting, the semantic soundness theorem only states that well-typed programs do not go WRONG (weak soundness), not that they produce answers of the expected type. To approach strong soundness, Duba et al. give an argument based on a continuation-passing- style (CPS) translation into the simply typed A-calculus. For programs of ground type, the denotation of an expression is the same as the denotation of its CPS transform with the identity function as an initial continuation, ie, E[e] S =E[CPS(e)(Ax.x)] D- Since strong soundness holds for the simply typed /-calculus, and (CPS(e)(Ax.x)) has the same type as e for programs of ground type, strong soundness holds for programs of ground type. However, the argument does not extend to higher types. For further details, we refer the reader to their paper [8, p. 169]. 2.2. Proofs Based on Structural Operational Semantics Tofte (36, 37]. Tofte reformulated Milner’s functional language with a structural operational semantics [27]. The semantics is specified as a deductive proof system; a conclusion E |e =>» of a deduction states that expression e evaluates to v in value environment E. A value environment is a finite map from variables to operational values. Values are either basic constants or closures, which result from the evaluation of 4-expressions. The soundness theorem again requires the definition of a semantic rela- tion (E) between operational values and types. For basic constants, the relation is explicitly specified by the function TypeOf; for closures, the rela- tion is defined by induction on types, and by evaluation at correctly typed argument values. The semantic soundness theorem states that if an expres- sion e has type t in type environment J, and if environment E respects F, and if e evaluates to a value v in environment E, then v possesses type t. TwEoREM (Semantic Soundness). If P>e:t and E:T and Ebe=v then = vt. SYNTACTIC TYPE SOUNDNESS 45 The proof is straightforward, and proceeds by induction on the depth of the deduction of E+ e=>v. Strong and weak soundness follow as before. Tofte turned to structural operational semantics in order to consider references, To this end, he reformulated the semantics with conclusions of the forms,E/e-v,s’, meaning that in environment E and store s, expression e evaluates to value © and the new store s’. The semantic relation now involves the contents of the store and the store typing (ST), a map from locations to the types of values stored there. The semantic relation 5: ST v:t may be read as “given the ST-typed store s, value v possesses type t.” Because of the possibility of cycles amongst references in the store, this relation is not definable by induction, but must be defined as the maximal fixed point of a monotonic operator on the appropriate space. The semantic soundness theorem states that if an expression e has type t in type environment J, and given store s of type ST, environment E respecting 1, and that e evaluates to v and store s’, then a typing ST’ can be found for s' such that v possesses type r. THeoReM (Semantic Soundness). If Poe:t and s:ST E:T and s, E}e=o, s' then there exists ST’ such that s': ST’ The theorem is proved by induction on the depth of the deduction of s, Et-e=», s’. Lemmas involving the semantic relation are proved using the technique of co-induction that Milner and Tofte developed for this purpose [21]. Leroy and Weis have successfully applied Tofte’s technique to show soundness for a different type system for polymorphic references [17]. Talpin and Jouvelot have also applied the technique to demonstrate soundness for a system that infers types, effects, and regions for references [35]. Duba et al. [8]. Duba et al. also present a proof of type soundness with respect to a structural operational semantics for a monomorphic language with continuations. The proof is an adaptation of Tofte’s technique; however, the semantics is significantly restructured, as the technique of defunctionalization [30] is used to represent the flow of control explicitly. The semantics has two judgment forms. The first kind of conclusion, E: K -e=>, indicates that expression e evaluates to answer v in environ- ment E and continuation K. The second kind of conclusion, v + K+’, indicates that continuation K evaluated at value v produces answer v’. As in the denotational case, two semantic relations are defined, indicating what it means for a value to possess a type (EF v:t), and for a continuation to accept a type (/ K::t). Like the denotational case, the theorem only establishes weak soundness. TueoREM (Semantic Soundness). If Poe: t and - E:T and & K and E; K -e=+0 then v# WRONG. 46 WRIGHT AND FELLEISEN It is not clear that the proof goes through in the presence of fixed-point operators [8,p.171], nor how to obtain strong soundness in this framework. 2.3. Discussion In each case above, the proof of soundness for a language or for a different formulation of a language’s semantics involves the use of a different proof technique. The techniques are often unrelated, so they provide no guidance in proving soundness for new languages or language features. A seemingly minor extension to a language may require a complete restructuring of its denotational or structural operational seman- tics, and may therefore require a completely new approach to re-establish soundness. For example, in introducing references to Milner’s functional language, Damas changed the domain equations for the denotational semantics to accommodate a store component, necessitating a completely different strategy for induction. In introducing the type dynamic, Abadi er al, again changed the domain equations, and extended the ideal model of types to match. To accommodate continuations, Duba e7 al. changed the domain equations yet again, also forgoing the tools developed by Milner and Damas. They used a separate argument to establish strong soundness. In introducing references to an operational formulation of the functional language, Tofte changed the form of judgments obtained by the semantics, and used the technique of co-induction to establish a proof. For continua- tions in a structural operational semantics, Duba et al. completely altered the semantics’, again changing the structure of the proof dramatically. Each of the above proofs considers a language with a single extension to a functional core. It is natural to ask whether two extensions can be merged, such that a natural union of the two type systems is sound. However, since each of the proofs involves a different technique, it is generally impossible to merge the proofs. Tofte’s proof for references and Duba et al’s proof for continuations give no direct assurance that STANDARD ML's type system is sound, even if the other features of STANDARD ML are ignored. 3. A SYNTACTIC APPROACH TO PROVING TyPE Sous S Our approach to type soundness is based upon an operational formula- tion of a language's semantics by rewriting. Each intermediate state of an * Furthermore, they take this as “evidence that the addition of [continuations] to Standard ML would be a substantial change, rather than an incremental modification, to the language” (8, p. 170]. However, we believe that this only indicates a problem with their semantic framework. SYNTACTIC TYPE SOUNDNESS 47 evaluation of a program is itself a program, and the evaluation of a program is performed by successive reductions into a new state: e,++e,+-+---. Reduction may either continue forever (ef), or reach a final state where no further evaluation is possible: e,t—»e, and ¢, + e, 41. Such a final state represents either an answer or a type error. Thus, proving type soundness reduces to proving that well-typed programs yield only well-typed answers. Programming language calculi, like the /-calculus, are the natural choice to specify the semantics of a language such that each intermediate step of evaluation is a program. Plotkin [26] shows how the semantics of a prototypical functional language relates to the J-calculus. The /-calculi extensions for state [12,14] extend this strategy to languages with references and similar constructs. Likewise, the control calculi [13, 14] can be adapted to address non-local control facilities such as exceptions and first-class continuations. Since the intermediate states of evaluation are programs, we may apply the type system to deduce a type for each state. Our strategy for proving type soundness rests upon two fundamental observations about the types of states. The first observation is that each intermediate state may be assigned the same type as the original program, i., reductions preserve type: if oe, :t and e, He; then Se: In combinatory logic, this property is known as subject reduction [4] The second observation is that sound type systems do not assign a type to irreducible expressions that are the sources of type errors, such as 1 +true. Furthermore, any expression containing such a subexpression is untypable; we call expressions containing such irreducible subexpressions fault) ife is faulty, there is not such that > e+. Together, these two observations imply that all final states that can be reached from a well-typed program are well-typed answers; ic., the type system is weakly sound. As all answers produced are well-typed programs, subject reduction also establishes strong soundness. To state that an answerv lies within the correct subset V* of values, we employ the type system itself: ee This yields a soundness theorem based on a syntactic connection between answers and types: if oe:t then either eff or erm and = vt. 48 WRIGHT AND FELLEISEN Strong and weak soundness follow from a syntactic soundness theorem with a definition of eval that takes faulty expressions to WRONG. In summary, proving a syntactic soundness theorem involves + demonstrating subject reduction, + characterizing answers and faulty expressions, and + showing that the faulty expressions are untypable. The structure of the proof always remains the same, whether or not the language includes some combination of references, exceptions, continua- tions, or other features. 3.1, Related Work Curry and Feys [4] introduced the notion of subject reduction for combinatory logic. In the language of combinatory logic, the CL-term e of a deduction concluding > e :¢ is called the subject, and the type t is called the predicate, Subject reduction states that reduction of the subject of a deduction preserves the predicate. Subject reduction holds for terms in CL and the A-calculus [33]. Mitchell and Plotkin [25] present a type preservation theorem, i.e. subject reduction, for a variant of the second order polymorphic i-calculus. This language has explicitly typed declarations; the proof of type preserva- tion is significantly simpler in the presence of such declarations. They do not develop a type soundness theorem. Adabi et al. [1] give a proof of soundness for type dynamic with respect to a structural operational semantics, in addition to their denotationally based proof, In their structural operational semantics, substitutions are carried out immediately: J-expressions evaluate to themselves, rather than closures, and judgments do not contain an environment component. Since answers are syntactic values, the type system can be applied to answers to show that evaluation preserves typing. Although this proof is similar to our proof of subject reduction, its extension to references or continuations apparently involves the same difficulties as Tofte’s and Duba e7 al’s proofs. 3.2. Road Map The next three sections illustrate our approach by proving soundness for several languages. Section 4 considers a functional language, similar to that considered by Milner [20]. Section 5 considers an extension to references, an extension to exceptions, and shows how the results may be merged to consider a language with both. To our knowledge, this is the first proof of soundness for exceptions. Section 6 illustrates soundness for an extension SYNTACTIC TYPE SOUNDNESS 49 providing first-class continuations, and is the first proof of strong type soundness for continuations in a polymorphic language. We conclude with a discussion of our technique and suggestions for its application to other languages. 4. Functional ML Functional ML is an applicative language with constants, call-by- value higher-order functions, and a Hindley/Milner-style polymorphic type system. A natural basis for a calculus of Functional ML is Plotkin’s untyped 2,-calculus [26]. Let Var be a denumerable set of variables and Const be a set of constants. The expressions and values of Functional ML are | eve, | let x bee, ine, (Expressions) ce) x] ¥ | axe, (Values) v where xe Var and c€ Const. The free variables, FV(e), and bound variables of an expression are defined as usual, with 2- and let-expressions binding their variables. The let-expression binds x in e, but not e,; ie, let bindings are not recursive. The fixed-point combinator Y provides recur- sion. Following Barendregt [2], we adopt the convention that bound variables are always distinct from free variables in distinct expressions, and we identify expressions that differ only by a consistent renaming of the bound variables. ClosedVal is the set of values with no free variables. 4.1. Semantics The calculus for Functional ML is based upon four relations, called notions of reduction: cv—+d(c,v) if d(c, v) is defined (6) (ixe)u—e[xr0] By) let x be vine—+e[xrv] (let) Y¥ v0 (Ax(¥o)x). (Y) To abstract from the precise set of constants, we only assume the existence of a partial function, 6: Const x ClosedVal —~ ClosedVal, 50 WRIGHT AND FELLEISEN that interprets the application of functional constants to closed values and yields closed values. The f, and /er reductions use substitution: the nota- tion e[x +0] means the substitution of v for free occurrences of x in e, renaming bound variables of v as necessary to avoid capture. The Y reduc- tion introduces an abstraction around (Yv) as v must be applied to a value (x does not appear free in p by the variable conventions). We refer to the union of these relations as v, or simply —> when there is no danger of confusion. The notion of reduction v gives rise to a system of reductions, —». The relation —» is the reflexive, transitive, and com- patible closure of +, ee ee, ea ey ee ee = C[e,J— Cle] C1 CeleC| let x be Cine | let xbee in C | Ax.C. A context C is an expression with one subexpression replaced by a hole, denoted [ ]. The expression C[e] results from placing an expression e in the hole of C; this operation may involve capture of the free variables of e by C. An equational system may be constructed as the congruence closure of v, but plays no rdle for our work. With an appropriate choice of 5, the calculus satisfies Church-Rosser and Standardization properties; the proofs are variants of Plotkin’s proofs for the 2,-calculus [26]. By Standardization, we know that an expression reduces to a value precisely if a reduction of lefimost-outermost redexes outside of abstractions leads to a value. Based on this idea, we can use the calculus to define an evaluation function [11]. Let +> be the relation E[e]t> E[e’] if e—e', (r>) where ]| Ee|vE|letxbe Eine. The special contexts E are evaluation contexts: they ensure that the leftmost-outermost reduction is the only applicable reduction in the entire program. Evaluating from left to right in an application is consistent with STANDARD ML. Unlike with C contexts, there is no possibility of capture when placing an expression in the hole of an evaluation context, because the hole cannot appear inside a binding construct. Let +» be the reflexive and transitive closure of +. Then the partial function eval is defined for closed expressions e as evaley=v ill erm. (eval) SYNTACTIC TYPE SOUNDNESS 51 It is easy to see that the decomposition of a program into a v-redex and an evaluation context is unique. It follows that the stepping relation (+> ) is a function, and therefore that eval is a function, too. 4.2. Typing The type system is a deductive proof system that assigns types to expres sions. The types of Functional ML are ee (Types) where 1), ... 1, are ground types for basic constants (int, bool, real, etc.), and a ranges over a denumerable set of type variables. A type variable stands for some fixed but unknown type. Function types, t,t, are right associative. The polymorphic type system allows certain variables to be used with a set of different types. For example, if the identity function 2x.x is tet-bound to the variable f, then.f may used as a function of type int -» int and applied to values of type int, or f may be used as a function of type bool > bool and applied to values of type bool. Type schemes represent such sets of types (a* means zero or more distinct type variables): oa Vart. (TypeSchemes) The free type variables FTV(c) of a type or type scheme are defined as usual, where Var,...2,.t binds a, through «, in t. We identify type schemes that differ only by a consistent renaming of bound type variables, or by a reordering of the binding occurrences. We also identify V.t with t, so types may be regarded as type schemes with no bound type variables. A type scheme Va... 2,. represents the set of types that may be obtained from t by substituting for «, through a,. This is formalized by the notion of generalization: a type scheme o generalizes a type t, written o >t, if there is a substitution for the bound variables of o yielding t. A substitu- tion S is a (partial) function from type variables to types. A substitution may be applied to a type in the obvious way; we write St. Substitution on type schemes respects bound type variables and is capture-avoiding. Generalization of a type is defined as Vayndyt >t if Stat (>) and Dom(S) = {a,... 4,} for some S. Generalization is extended to type schemes o>o' iff whenever o’>rt then o >t. (>) 52 WRIGHT AND FELLEISEN Some examples are tT} Va.a— a > int int Vay a2.%1 +g > int + bool Veat+ a > a1y > 3 Wort.) + oy > Woy.aty ar. Generalization is a partial order on type schemes. In order to assign types to open expressions, assumptions about the types of free variables are provided by type environments, denoted I. Type environments are finite maps from variables to type schemes. The free type variables FTV(I>) of a type environment are the free type variables of the type schemes in its range. For stating and proving various lemmas, it is convenient to define substitution on type environments pointwise; i. SCLC, 1s oy Xn On PI= (KX SO1, oy (Xn SGD} The function TypeOf: Const» TypeSchemes associates a type scheme with every constant. Since we have not precisely specified the set of con- stants, Functional ML is really a class of languages parameterized by the set Const and the functions 5 and TypeOf. Just as the Standardization and Church-Rosser properties restrict the admissible set of 5 functions, a particular choice of Const, 5, and TypeOf must satisfy a typability condi- tion for type soundness to hold. For every ¢, t, 1’, and v, if TypeOf(c)>t' > rand ov: (-typability) then 3(c, v) is defined and & (c, v) : 7. This condition requires that 5 be defined for all constants of functional type and arguments of matching type, and restricts the set of results that 6 may produce. This rules out, for the moment, functional constants such as division that are not defined on all values of their input type. A type judgment [> e:t for e an expression of Functional ML is the conclusion of a deduction constructed according to the inference rules in Fig. 1. The judgment [> ¢:+ is read “in type environment I, expression ¢ has type.” If the type environment in a judgment is empty, we write me: t. An expression ¢ is a well-typed program if it is closed and there is a judgment & e:t. In this formulation of the typing rules, only one rule is applicable to an expression. Hence if there is a deduction assigning an expression a specific type, that deduction is unique. This permits proofs by induction on the structure of a deduction for a type judgment to proceed by case analysis on the structure of the expression of the type judgment. SYNTACTIC TYPE SOUNDNESS 53 Por: if M(2j>r (var) Poe:r if TypeOf(c) > r (const) PeYi((nan)onon) 1m (Y) Pen nlee:r a Ce as ect | feainon Cee:n (app) Teaeain Peein Plzr Close(n, Pjoer: TPolet bee; inez:t (let) Close(r, P) = You. 0y.7 where {01,-..@n} = FTV(r)\ FTV(P) Fic 1. Typing rules for Functional ML. This type system has the important property that there is an algo- rithm # to determine whether an expression has a type [20]. Given a type environment and an expression, the algorithm computes a substitution and a type. The algorithm is sound [20] with respect to the type system, meaning that it infers only valid typings THeoREM (Soundness of ) [Milner]. If (S,t)=W (Pe) succeeds then ST > The algorithm is also complete [5], meaning that if an expression has a valid typing, then the algorithm will find a typing. Furthermore, the algorithm always terminates. TueoREM (Completeness of #) [Damas, Milner]. If S;Pe:t, then (S,t)= WL, e) succeeds and there exists S’ such that S'(ST)= Sf and S'Close(t, ST) >1;. If WU, e) does not succeed, then it stops with fail. Proving completeness involves demonstrating that if an expression has a type, then it has a principal type, of which all others are substitution instances. Tueorem (Principal Typing). If Pee :t, then there exists + such that Te:t and whenever Poe:t, then Close(t,I')>t;. The type t is principal for e in I. The existence of a sound and complete algorithm establishes the decidability of the type system. However, this is solely a property of the type system, and says nothing about the relation of the type system to the semantics of the language. 54 WRIGHT AND FELLEISEN 4.3. Type Soundness Our proof of type soundness rests upon the notion of subject reduc- tion [4]. The subject reduction property states that reductions preserve the type of expressions. Lemma 4.3 below extends subject reduction to Functional ML. Subject reduction by itself is not sufficient for type soundness. In addi- tion, we must prove that programs containing type errors are not typable. Put differently, if an expression e¢ is irreducible due to some type error, say (/10), then the type system should not be able to assign a type to the expression. Otherwise, a well-typed program could reduce to such an expression without violating subject reduction, and still cause a type error to occur. We call such expressions with type errors faulty expressions and prove that faulty expressions cannot be typed. Some obvious facts about deductions that we use with no more ado are: (i) if > Cle]: then there exist ’ and ¢’ such that F’> e (ii) if there are no /",7' such that [ce :7’, then there are no Pt such that [> C[e]:t These follow from the facts that (1) there is exactly one inference rule for cach expression form, and (2) each inference rule requires a proof for each subexpression of the expression in its conclusion. Several facts about generalization follow from the definition of Close: (i) if o’ > then Close(t,, [xt 0’)}) > Close(t,, Px a]); Gi) if x¢Dom(F) then Close(t,, PF) > Close(t,, Px o]). The following lemma states that extra variables in the type environ- ment I of a judgment "te: r that are not free in the expression e may be ignored. Lemma 4.1 Uf D(xj=I(x) for all xeFV(e), then Toe:t iff Dicest A key lemma that we use in the proof of Subject Reduction for Functional ML and its extensions is the Replacement Lemma, adapted from Hindley and Seldin [16, p. 181]. This allows the replacement of one of the subexpressions of a typable expression with another subexpression of the same type, without disturbing the type of the overall expression. LemMA 4.2 (Replacement). If (i) @ is a deduction concluding P'> Cle,]:1, (ii) G is a subdeduction of Y concluding Fe, :1', SYNTACTIC TYPE SOUNDNESS 55 (iii) occurs in B in the position corresponding to the hole ({ }) in C, and (iv) Piet, then P'> Cle] :1. Proof. We think of deductions as trees with the conclusion at the root. Let 2, be the deduction concluding [> e,:1'. Cut the subtree 2, out of @ and replace it with %. Replace all relevant occurrences of e, in the resulting tree with e,. Then the resulting tree is a valid deduction concluding > C[e,] :z, as may be shown by induction on the height of the tree [16,p.181]. Subject reduction for Functional ML states that the reductions of v preserve type. MAIN LEMMA 4.3 (Subject Reduction). If [> e,:t and e,—+e; then Poe;:t. Proof. The proof proceeds by case analysis according to the reduction een. Case cv—+6(c,v). Then Pe e:t' +t and Pe v:t! follow from P= ¢v:t by app. Hence "> 4(c, v) :¢ by the d-typability condition. Case (Ax.e)v—>e[xt+v], From Pe (ixe)v:t we have Pov: 1! and Pe dxe:t' +1 by app. From the latter, [[x++1'] > e : + follows by abs. Hence > e[xr+v]:¢ by Lemma 4.4. Case let x be v in e—re[xrov], From let x be v in e:t we have Pw:t’ and [Lx++Close(t’, P)] > e:7 by let. As Close(s', 2) = Vat nth 2, Where {2,5 on On} = FTV(t')\FTV(L), we have Pe e[xr+v] zt by Lemma 4.4. Case Yo —+ v(Ax(¥e)x). From Me Yv:t, where t=1, +12, by Y and app Poni (t) >t) tot. a) Then from P= Yo: , P[xenJeYe:t, +2, by Lemma 4.1, PExret]&(Yo)x:t, by app, Poe dx(¥e)xity >t by abs, Fo v(ax(¥e)x):t; 1, by app with (1). This completes the essence of the proof. It remains to establish several lemmas. f 56 WRIGHT AND FELLEISEN A Substitution Lemma is the key to showing type preservation for reductions involving substitution. Lemma 4.4 (Substitution), If 7[x++Va,...0,.t] > e:1’ and x¢ Dom(L) and Pvt and {2,5 25 %q} OFTV(E) = Q, then Pm e[xrrv] i’. Proof. We proceed by induction on the length of the proof of Txt? Wot...0,.7] e: 1’, and case analysis on the last step. Case e=c. Then TypeOf(c)>t’ by const, and thus ec: 2’ by const. Then Pe c[xr+v]} 21’ since c[xrev]=c. Case e=x', If x’ #x, then Px’ >’ by var, and [> x’: 1’ again by var. Hence P= x'[xi+v]:1' since x'[xrov] =x’, If x’ =x, then by vat TUX Ws on tet) > hey Vaya @yt > T's ie, we can find a substitution S with domain {2,,..., 2} such that St=" Next, we have SP v:St by Lemma4,5 since P>v:t, and therefore SPev:t’, But Dom(S)nFTV(L)=@, so SP=P. Also x[xrv] =, hence > x[xrrv] it’. Case e=1x'.e,. By abs, it follows from the assumption [x-+ Vet, 8 T] > Ax’.e, : 0 that t’=1,-> 12, and TUX Vat tty TIER 1] ey ta, ie, PExte ty] Lx Vaya. te] > ety Choose a substitution S$: {a,,.., 4%} —r {2;, 0%} such that oi, 0, 4, nq» and FTV(P) are all distinct. Then Ux! hs Sty ]LxH 9 Woy...at,. 7] e) St. by Lemma 4.5, (2) TUx'+StJoo:t by Lemma 4.1,and (3) FIV(T[ x! St,])0 {244 04 Mm} =D by the choice of S. (4) Thus, [[x't> St,]>e,[x++v]:St, by the inductive hypothesis with (2), (3), and (4). Since S is a bijection, S~' exists; hence SUL[x! H+ Sty] > e,[xr+v] :S-(Se,) by Lemma 4.5; ie, PEx'rerJee [xr]: t, SYNTACTIC TYPE SOUNDNESS 37 But then Po dxiey[xivv]:t, >t, by abs; ie, Pe (Ax'.e))[xrrv] ty >t. Case e=(e,e2). From FL xt+Vay...%qt]&(e,e2):1', by the first premise of app TUX ay GT] Oo! Poe lxev]:t;+1 — byind. hyp. (5) By the second premise of app PU Vat et Poee[xtev]:t, — byind. hyp. (6) Then by app with (5) and (6) Pe (e[xrvleferv]):t; ie, Fe (ee,)[xrvv]: 7. Case e=let x’ be e; in e,. By the first premise of let TLR Vat tT] ey 20, Pee [xv] by ind. hyp. a) By the second premise of let PLR Vat tty TL 9 Close (ty, PL Woy... tI) > eg 1” ie, Lx’ rs Close(ty, FLX Way... y. TIV] [XH Wot, oo tty Tt] e2 it’. (8) Since Po v:t TL x' b+ Close(t,, Px Vay... t])J>v:t — byLemma4.t. (9) Now {ots ny ty} OFTV (PL x! + Close(ty, DEX Wa ..-0%q.7)))) S (4. oy On} O(FTV(L) U FTV(Close(t,, PL x Woy...%9-T]))) = (1, oy On} OFTV(Close(t,, FLxt Wey...%,-7])) = {015 25 Oe} A CFTV(t1)\(FT V(t )\ FTV LX Va... ]))) {oy ny ty} AETV (ty) 0 FTV (Lx Vay. O97) 58 WRIGHT AND FELLEISEN youn By} O (ETVIP) U FTV (Wey 2: t)) py ig} FTV (Wty) yy ny Og} (FTV (t)\ {4 5 oy nb) so by the inductive hypothesis with (8) and (9) TLx! H+ Close(ty, [xt Vary ..%y.t])] egLxre 0] :” T[x'++ Close(t,, PJ >e,[xtv]:t’ by Lemma 4.6, Teletx’bev;[xv]ine,[xr+v]:t’ — byllet with (7), ie, Po (letx' bev, ine,)[xrv]:c. Lemma 4.5 establishes that typing is stable under substitution. Lemma 4.5. If [> e:t and S is a substitution then SP'> e: St. Proof. The proof proceeds by induction on the length of the proof of ee: and case analysis on the last step. The proof is an adaptation of Tofte’s proof of a similar lemma [37, Lemma 4.2]. Finally, Lemma 4.6 shows that generalizing the type of a variable in the type environment has no impact on the conclusion of a deduction. Lemma 4.6. If [Ext+a]oe:t and a’ >a then [[xrvo']oe:t. Proof. The proof proceeds by induction on the length of the proof of T[x+o]>e:t and case analysis on the last step. The proof is an adapta- tion of Damas and Milner’s proof of a similar lemma [5, Lemma 1]. The only interesting case is the case for let-expressions. Case e=let x’ bee, ine,. By the first premise of let Thx o]ee, Thxeo'}ee:t, — byind. hyp. (10) By the second premise of let Tixteo][x' rH Close(t,, MExtea])]> 2:1 Tixvea'][x' ++ Close(t,, Fixeo])]=e2:t by ind. hyp. TUxeso']Lx'++ Close(t,, Mxt+o'])]=e2:t — byind. hyp. (11) Then P[xt+o"] > let x’ be e, ine, :z by let with (10) and (11). A corollary of Subject Reduction is that standard reduction steps preserve type. SYNTACTIC TYPE SOUNDNESS Se Corottary 4.7. If Pe e,:t and ewe, then Pee, :t. Proof. First, if e, +e, then e, = Ele] and e, = E[e’] and e— e’, so Ie, :1 by the Replacement Lemma. Then the result follows by induction on the length of the reduction sequence e,—»e3. Subject reduction ensures that if we start with a typable expression, we cannot reach an untypable expression through any sequence of reductions. This by itself, however, does not yield type soundness. Subject reduction simply ensures that any properties implied by typability are preserved by reduction. The critical property we seek is that evaluation of a typable expression cannot get stuck. Dernyrmion 4.8 (Stuck Expressions). The evaluation of an expression ¢ is stuck if e is not a value and there is no e' such that e+e’. Of course, whether an expression eventually reduces to a stuck expres- sion is not a decidable property. We approximate the set of expressions that become stuck with a set of faulty expressions. Deriimion 4.9 (Faulty Expressions). The faulty expressions of Func- tional ML are the expressions containing a subexpression (cv) where 6(c, ©) is undefined. The idea is that any faulty expression may become stuck; ie., the property “reduces to a faulty expression” is a conservative approximation to “reduces to an expression that is stuck.” Thus the faulty expressions are a superset of the stuck expressions. For example, the expression ((Zy.2)(Ax.+1 true)) is faulty because of the subexpression (+1 true), but is not stuck because it reduces to 2. The behavior of evaluation is summarized by the following lemma. Let ef} mean that e diverges; ie., e +--+ e’ for some e’, and for all e’ such that etre’, there exists e” such that e’ +e". Lemma 4.10 (Uniform Evaluation). For closed e, if there is no e' such that e+—»e' and e' is faulty, then either ef} or ev. Proof. By induction on the length of the reduction sequence, we need only show that either e is faulty, e+—>e’ and e’ is closed, or ¢ is a value. From the definition of ++, etre’ iff’ e = E[e,], e’ = Ele], and e, — (Recall that E::=[ ]| Ee|vE|letxbe Eine.) We proceed by induc- tion on the structure of e. Case e=c,Y, or Ax.e. Then e is a value. Casee=x. Since e is closed, this case cannot occur. ean ni5ns 60 WRIGHT AND FELLEISEN Case e = let x be e, ine,. By the inductive hypothesis with e,, there are three cases to consider. If e, is faulty, then let x bee, ine, is faulty. If e,=E\[e’] and ee" then e = E[e"] where E=let x be £, ine); thus e+ Ele]. Otherwise, ife, is a value, then let x be e, ine; > e,[x >}. Case e=(e,e;). By the inductive hypothesis with e,, there are three cases to consider. If e, is faulty, then (e,¢3) is faulty. If e, = £,[e"] and e’—»e” then e = E[e’] where E= (Eye); thus e +» ELe”]. Otherwise, e, is a value. By the inductive hypothesis with e,, there are three subcases to consider. If e is faulty, then (e,e;) is faulty. If e;= E,[e’] and e’—+e” then e=E[e’] where E=(e,£,); thus e+» E[e”]}. Otherwise, both e, and e, are values, and the possibilities can be summarized as follows: > or b+ or tor © | faulty faulty faulty oe — od ad x = 2 i. be x x x x x x Cases marked with x cannot occur because the expression is not closed. Cases marked with + indicate that the combination reduces with E£=(). 1 To relate faulty expressions and typability, we show that no faulty expression is typable. Main Lemma 4.11 (Faulty Expressions Are Untypable). /f e is faulty, there are no I, such that Pe :t. Proof. It suffices to show that the subexpressions of ¢ that cause e to be faulty are untypable. In general, we proceed by case analysis according to the form of the subexpression, but for Functional ML there is only one case. Suppose (cv) is faulty and Pocu:t. By app, Poc:t' +r and Pov: tc’. Then by the é-typability condition, 5(c, v) is defined, but this contradicts the assumption that (co) is faulty. Since the faulty expressions are untypable and we have type preserva- tion, the property “does not reduce to a faulty expression” is implied by typability.* ‘Type preservation by itself does not guarantee type soundness. Consider the (trivial) type system where every type is a subtype of every other type. Type preservation holds since every expression can be assigned every type. However, the system does not prevent type errors, because it rejects no expressions. SYNTACTIC TYPE SOUNDNESS 61 TuEoREM 4.12 (Syntactic Soundness). If oe:t then either ef} or ere and Sv: t. Proof. By Uniform Evaluation, either ¢ —» e’ and e’ is faulty, or ef, or etn, Since &e:, Subject Reduction implies &v:t and De’: Suppose et—»e’ and e’ is faulty. Since faulty expressions are untypable, e':t is a contradiction; therefore this case cannot occur. Hence either ef orer—»vand oo:t. ff To state strong and weak soundness theorems, we must have a definition of evaluation that differentiates between programs that diverge and those that cause type errors. Let answers (a) be values or the special result WRONG, and define eval’ as WRONG if et—»e' and e’ is faulty; v if ern. eval’(e) -{ (eval’) Programs that cause a type error return the special answer WRONG. Strong and weak soundness are now corollaries of Syntactic Soundness THEOREM 4.13 (Strong Soundness). If > Sart. and eval'(e)=a then TueoreM 4.14 (Weak Soundness). Jf > e:t then eval'(e)# WRONG. 5. REFERENCES AND EXCEPTION Besides functional facilities, first-class references and exceptions are the most important core programming facilities of STANDARD ML and similar languages. In this section we consider several extensions to Functional ML. The first subsection deals with Reference ML, an extension of Func- tional ML with references. It uses our previous work on a calculus of state, 4,°S [12,14], and in particular its cell-oriented variant [3]. The second subsection addresses Exception ML, an extension of Functional ML with exceptions. It uses a modified version of our control calculus, 4,- C[13, 14], especially its fragment with prompts [9]. The final subsection presents Core ML, which includes both references and exceptions, Sil. Reference ML Extending the Z,-calculus to a calculus of functions and references requires extending the syntax with a new kind of expression and several new values (underlined } 62 WRIGHT AND FELLEISEN v | ere; | let x bee, ine; | pb.e (Expressions) vrse|x/¥]ixe|ref|!| (Values) O2= {Cy vy}* The expression p-€ binds Xyy 5X, IN Vj, 4 Py and e. Above, @ represents a finite function from variables to values, i., we treat 8 as a set of pairs whose first components are distinct. We also identify p-expressions that differ only by a consistent renaming of bound variables. The values ref, !, and := are the familiar operations of ML.5 The application of ref to a value creates a reference cell containing that value. The application of ! to a cell returns the value contained in that cell. The binary assignment operator := evaluates both its operands, the first of which must evaluate to a cell, and assigns the value of the second operand to that cell. Since all operations are curried, the application of the assign- ment operator to a variable is a value. Specifically, the expression (:= x) may be thought of as a capability to assign to the cell x. The p-expression is semantically an abbreviation of a let-expression, PRX Orden X pe Vg HL let x, be ref u, in let x, be ref u, in OP Pndas ns WC x10). nbn der where u,,.., u, are arbitrary values (of the right type). In order to simplily the semantics, we do not treat it as such [14]. Intuitively, a p-expression plays the réle of a store fragment during the reduction of a program with imperative assignment statements. A reference cell is represented as a variable; the pair .REL] — p8Cx, 0). REP] (deref) pO p0,0,.¢ (Pmerse) R[p0.eJ—+p0.R[e] if R#L). (Pup) By the variable conventions, x is not free inv in the ref reduction: the domains of 8, and 0, are disjoint in Pyeges and the free variables of R are disjoint from the domain of @ in pyj. We refer to the union of these five reductions as r. The notions of reduction r and v (adapted musatis mutandis to the full syntax) form the basis for a calculus of functions and references. We refer to the union as vr, and write" for a reduction in wr. The extended notion of reduction gives rise to a system of reductions and equations with the extension of contexts to: | CeleC|letxbeCine| let x be ein Cj Ax.C | p8.C | pO is a function requires a simple diamond theorem, since the order in which pjy, and Pmerge Feductions happen is not fixed, and the context R in the py rule is selected in a nondeterministic fashion. The answers returned by evalua- tion of a program are no longer simply closed values, since an answer may be a reference cell. Answers are values or p-expressions enclosing values: v | pOv (answers) Based on these definitions, evaluation may be defined as before: eval,(e)=a iff eroa. (eval,,) 5.1.2. Typing Typing reference cells in the presence of polymorphism is not straightforward, as the obvious solution is unsound [6, 36, 37]. To assign SYNTACTIC TYPE SOUNDNESS 65 types to reference cells, we extend the set of types with an additional constructor: lett lalty tp] ref The type t ref is the type of cells containing a value of type t. The obvious types for the three operators are indicated by their semantics: Pe ref:totref Politrefor To : rrreforot. For example, the first argument of the assignment operator (:= ) must be a reference cell. The second argument must be a value matching the type of the cell. The result is of the same type as the second argument since our assignment operator returns the value assigned. The following expression illustrates why this typing is unsound: let f be ref (4y.y) in (22. 1f true)(:= fn. +1). If the type of the reference bound to x is generalized to Va.(a—» 2) ref, then the reference cell can be treated as having type (int > int) ref for the assign- ment, and as having type (boo! > bool) ref for the deference; hence this expression is typable as bool, But evaluating this expression leads to a type error: let f be ref (Ay.y) in (az. If true)(:= f(An. +19) y).xin f(in. +1) —» let fhe p pXx, dyy>. (az. Ix true)(:=x(4n. +11) —» pdx, in. +1 n>, Lx true —» px dn. +1). +1 true. As Tofte [36, 37] points out, the problem with the obvious typing is the generalization of type variables that appear free in the type of a value in the store. The central idea of Tofte’s solution is to ensure that the only storable values are those that will not be used polymorphically at run-time. To this 66 WRIGHT AND FELLEISEN end, type variables are partitioned into imperative and applicative variables: the former set of type variables is named JmpTypeVar; the latter AppTypeVar. Types are classified accordingly: an imperative type cannot contain any applicative type variables. Only values of imperative type can be stored. When the type of a value is generalized in a let-expression, type variables that might appear in the types of values in the store are required to be imperative, and are not generalized. The notion of generalization requires appropriate adaptation. We still have Voyutpt’ >t if St’ =rand Dom(S) 5 on ty} for some S, (>) but the substitution § is required to map imperative type variables to imperative types. Thus, if g is an imperative type variable, we have Vag» ¢ > int > int since x is potentially applicative (the meta-variable 2 still represents any type variable—imperative or applicative). Like all other techniques for typing references, Tofte’s system requires modifying the typing rule for let-expressions. The let rule is split into two tules, according to whether or not the right-hand side of the declaration is a value. Figure 3 gives the new rules, The second rule does not generalize ‘over imperative type variables, and thus will not generalize the type of a value in the store. However, if the expression bound by a let-expression is a value, as in the first rule, then its evaluation cannot create a new cell, so generalization of imperative type variables in its type cannot generalize the type of a value in the store. Tofte uses the terminology expansive and non- expansive to denote this syntactic classification of expressions into those that may create new references, and those that definitely do not create new references. Like Tofte, we classify only values as non-expansive, but a stronger type system is possible by classifying more expressions as non- expansive [36, 37] Peein Pen Coun. t)eein on Feiet 2 be vine 272 Ferrin ler AppClose(n P)ees tet Values a Felts ber inva t, Closer P) = Woy coset where ferns soos tha) = BPVUD\ BTV) (ETY (9) PFVUN) 2 App Pape Var AppC'tose(r, PY = Wer. .0ey.7 Where {ett Atn Fi. 3, Modified let-expression typing rules. SYNTACTIC TYPE SOUNDNESS 67 Ports —+rref if ris imperative (ref) re gt dee (deref) Povs:(rref rr) (assign) Player ref]. bene ta nef]ee rr Pizy en ref]. fzw ta ref]> ost Tis imperative 1 .RE! x] + p0.R[v]. From Pe p8 pO e' zt by Lemma 4.1* with (21); ie, PLxpro ty ref Ext AppClose(t’, PJ e’ st. 70 WRIGHT AND FELLEISEN But each 1, is imperative, due to the restriction on the typing of p-expres- sions, hence AppClose(x’, P) = AppClose(z’, PEx;+t, ref). If R'[e] is expansive, then Tx; t ref [Lees AppClose(2', PLxi 1, ref W]e eit TLx,+ 1 ref]> let x be R’Le] ine’: by let, with (23) Te p0.let x be R[e]ine’:t by rho with (22). Otherwise, R’[e] is non-expansive, and TEx, 1, ref [Lx Close(s', PLxir t,ref e's T Lx, 1 ref]> let x be R’Le] ine’: by let, with (23) I'm pO.let x be R'[e]ine’ :t by rho with (22). Thus > p@.R[e]:+ by induction. It remains to extend the proofs of the various lemmas. The only one that is not straightforward is the Substitution Lemma. As in the definition of generalization, substitutions S in the following proof are required to map imperative type variables to imperative types. Lemma 5.3 (Substitution). f xt Wa,..,.t]>"e:1' and x¢ Dom(L) and Pom" yt and {0,5 14%} OFTV(D)=@ then Pom! elxre] it Proof. The cases from the proof for Functional ML are unchanged, with the exception that the let-expression case applies only when the bound expression is a value. There is one new case for expansive let- expressions, and new cases for the additional syntax. Case e=ref.!, or =. In each case, [ee:t' for any I”, hence Pee: Also in each case, e[x++r] =e, so Pe e[xrrv] :0' Case e=pb.ey. From Fx Va..0,.1] > ple, it’ by rho TUX Way dy TLR ty ref] eit, and TD Wate ty TEX 1, ref > ey 0 where 6 = (x1, 0, )..(Xms Bm ds Xis on Xr ¥ are distinct, and each t, is imperative for 1 (05 sy Hy} such that @,..., 2, are distinct type variables, Sz,=2', and {2/,... a} 0. (ft) sos Sn} UFTV(D) U FTV(t')U U, FTV(2,)) = @. Then by Lemma 4.5* SYNTACTIC TYPE SOUNDNESS n SUPLx HV ty. TILK, t, ref ]) > v, : St, jie, P[xre Vaya). t] Lx, St, ref] > v, : St, ie PEK ee Sty ref [Lx Wet, nt TO 0,2 Sti. Also, by Lemma 4.5+, SULT Wet tg TILK; 7, ref > ey | St" je, PEM Vay ut, TIL St, ref] > ey: St! je, PExj-+ St, ref [xr Vaya, tT) > e, St By applying the inductive hypothesis to each, FLx,++ St, ref Jo v,[xr+ 0] : St, and Tx) St, ref ]>e,[xtov]: St’. Since S is a bijection, S~' exists; hence Thx tjref]eo[xev]:t, and Thxretref]>e,[xrev) :7. Then Pe pO[xrv].e, [xt v]:1' by rho; thus Pe (p6.e,)[xrv] 7’. Case e=let x’ bee, ine where e, ¢ Values. By the first premise of let, PL Woe tty CJ Cy 2, Poe [xer]:t, by ind. hyp. (24) By the second premise of let, Tx Vat, tty Lx! H+ AppClose(t,, FLX Vay. tJ ey :0’ fie, Lx’ +> AppClose(ty, FLX Vat, uy. t]) JL xt Way ..tty. 1] > ey 27 Choose a substitution S$: {2),.-.%,} \JmpTypeVar—> {a/,, ... ay} such that aj,.., a, are distinct imperative type variables, S is a bijection, and {as Miu} O(ETVE) O FTV(t) U {0t,, oy y}) =. Then by Lemma 4.5* SUF Lx! + AppClose(t), FLX Ver, ..%_.t})] [xe Vay ..a,.t]) > ey: Se? ie, PEx'H+ 8 AppClose(t,, Px Vat, 9.) [xt Vary tty. 2) > eS! ie, PLx' + AppClose( Sty, FLX Vat, %q-1))] (25) Le Vay aaty t)) > es St’ otis 72 WRIGHT AND FELLEISEN since the domain of S contains only imperative type variables. From Fev: since x’ is not free inv P(x! > AppClose( Sty, FLX Va .0%4.t))] > vt. (26) Now, {15 20 ty} OFTV(LX' H AppClose( St, FL xt Wats %y.tJ)J) S (245 on On} (FTVP) U FTV AppClose( Sty, DEX + Ver. %y.7))) = 1 5 Mn} AETV AppClose( Sty, FL xr Wot, «-%y-T])) = (p52 by} O FTV (Wa. 0%.St)) = (psy te (FTV St {00, ons Hin) where {ai, ...0%,} = (FIV(St,)\FTVUE Lx Way ..0y.0])) 0 AppTypeVar. By the inductive hypothesis with (25) and (26), it follows that PL x! > AppClose(St,, PDX Wot, ty. t))] & eg [xr v] : St’. Since S is a bijection, S~! exists, so by Lemma 4.5* So 'PLx' > AppClose( Sty, PL x-+ Wat tty. T])]) > e [xe v] : S“(S1’) ie, Lx’ H+ AppClose(t,, PU x Vat, ty. TI) > eg [xr 0]: Then by Lemma 4.6* Tx! AppClose(t,, P)] > e,[xrv]:t" and by let, with (24) Pe letxbee,[xrv] ine,[xro0]: 1° ie, Pe (letxbee, ine,)fxoo]:t. The evaluation of an expression in Reference ML can become stuck for several new reasons. The expanded definition of faulty expressions reflects this fact. Derintrion 5.4 (Faulty Expressions). The faulty expressions of Refer- ence ML are those expressions containing a subexpression of the form SYNTACTIC TYPE SOUNDNESS 73 (cv) where 5(c, ») is undefined; (1v) where v¢ Var; (:=) where v¢ Var; or pO¢x, v2>.CLx vy]. As before, we have a Uniform Evaluation Lemma, stating that programs either yield an answer, diverge, or reduce to a faulty expression. Lemma 5.5 (Uniform Evaluation). For closed e, if there is no e' such that e “'» e' and e' is faulty, then either ef} or et» a. Proof. The proof proceeds by induction on the length of the reduction sequence, and is similar to the proof for Functional ML. f All of the expressions in the expanded definition are untypable. MAIN LemMa 5.6 (Faulty Expressions Are Untypable). [f e is faulty, there are no I and + such that P=" e 1. Proof. Again, it suffices to show that the subexpressions of e that cause e to be faulty are untypable. We proceed by case analysis according to the form of the subexpression, assuming for each case that the expres- sion can be typed, and deriving a contradiction. Case (cv), where 6(c, v) is undefined. As for Functional ML. Case (1v), where v¢ Var. Assume that Po !v:t. Then Pou:tref by app and deref, which implies v is a variable (since no other value can have type t ref), contrary to the assumption. Case (:=v), where v¢Var. Assume that [> eee vit’ ref where t=’ 1’ by app and assign, which implies v is a variable, contrary to the assumption. Case p0 p6 xv:t, where P'(x)=P"(x), FP" x:t, >t, by app, hence P"(x)>t, 12. This contradicts ["(x)=t' ref. Type soundness now follows as before. Turorem 5.7 (Syntactic Soundness for Reference ML). If >"e:t then either ef} or et» a and >"a:t. Proof. Exactly as for Theorem 4.12, using the appropriately extended lemmas. ff 14 WRIGHT AND FELLEISEN 5.2. Exception ML Due to 4-typability, constant functions must be defined for all values of their input type. This precludes constants, such as integer or real division, that are defined on all but a few recognizable input values of correct type. STANDARD ML solves this problem by introducing exceptions. Our exception extension provides named exceptions with parameters, a means of raising exceptions, and a means of handling exceptions. Our extension thus includes three new phrases: exception x,..x,ine, raise e,e,, es handle e,e, The first phrase declares x1, .., X, to be exception names lexically bound ine. The second phrase requires ¢, to evaluate to an exception name, and raises that exception with a parameter, the value of e,. The parameter propagates along with the exception, and is used at the site where an exception is handled. The third phrase evaluates its subexpressions e, and ey first, and installs the value of e; as an exception handler for e, excep- tions that are raised during the evaluation of e;. The subexpression e, must evaluate to an exception name, and e, must evaluate to a function that accepts parameters of e, exceptions. When an exception is raised, control transfers to the dynamically closest handler for that kind of exception. The handler function is applied to the exception parameter, and the result of the application is returned as the result of the handle-phrase. If there is no active handler for a raised exception, evaluation terminates with an “unhandled exception” answer. To extend Functional ML with exceptions, we add several new phrases to the syntax: » | e,e2 | let x be e, in es | exception x ine (Expressions) c|x|¥ | 2xe| raise | ehandle | raise v | e handle v (Values) In the expression exception ; in e, the variables in 7 are bound in e. We treat z as a set of variables, and call these exception names. As raise is a curried binary operator, the application of raise to a value is a value, and is included in the syntactic class of values (like:= in Reference ML). Likewise, the expression e handle is a value, and receives an exception name and handler function by ordinary application. Hence the application of e handle to a value is also a value. SYNTACTIC TYPE SOUNDNESS 78 5.2.1. Semantics Raising and handling exceptions requires several new reductions: Ufraise xv]—+raisexy if UAT] (raise) (raise xv,) handle x v.— 0,0, (handle ) exception yx, x, in exception 7x, x; in (reraise) X[ (raise x,v,) handle x,v,]— —X[raise x,v,] MAR v; handle x v.—+. (unhandle) These new notions of reduction again rely on (two different kinds of) contexts for the enforcement of a specific order of evaluation for applica- tions in connection with the raising and handling of exceptions: u x []|UVel|vU|letxbeU [1|Xe|vX|letxbe Xine|Xhandlexv. (handling) e (raising) When an exception is raised, raise reductions propagate the exception out- wards, eliminating pending computations. As U contexts do not include the phrase U handle x v, raise reductions propagate the exception only to the closest exception handler. If the closest handler matches the raised excep- tion, a handle reduction applies the handler function to the exception parameter. If the handler does not match the exception, a reraise reduction discards the handler, and the exception may continue to propagate by raise reductions. Should an expression protected by a handler evaluate to a value without raising an exception, the unhandle reduction discards the handler. The exception-expression requires two additional reductions, similar to those for p-expressions:” exception 7, in exception 7, ine (XM perge) — > exception z,x, ine [exception zinc} (ext) —+ exception yin X[e] if ¥¥[ J. Indeed, the only difference is that the exception-expression does not bind any values to its variables. The purpose of an exception-expression is to * Due to our use of the variable conventions for ex?nmrxes OUF exceptions are generative as in STANDARD ML (22, 231} 16 WRIGHT AND FELLEISEN distinguish different exceptions in the reraise reduction, in order that evaluation be deterministic. If x, and x, are different but only J- or let- bound, subsequent reductions may substitute them to the same excep- tion-bound variable. making the raise reduction applicable. For example: exception x in (2y. 4z. (raise y v,) handle z v,) x x —» exception x in (raise x v,) handle x v, —» exception x in v,0;. Insisting that x, and x, be exception-bound in reraise ensures that they refer to distinct exceptions. The reduction handle does not require its variables to be exception-bound, because substitution necessarily replaces both instances of x in the handle redex with the same exception name. We use x to refer to the six reductions for exceptions introduced above. Taking the union of v (extended to the full syntax) and x yields vx, the notion of reduction for Exception ML. With evaluation contexts extended to E:=(]|Ee|v£|letxbe Eine | exception zin £| Ehandle xv, the stepping function "> may be defined along the same lines as before. Answers for eval,, are a:=0 | exception z in v | exception zx in raise xv. (answers) Answers of the third form are unhandled exceptions: since handlers are dynamically bound, it is possible for an exception to be raised when no handler for it is installed. Evaluation is defined as eval,,(e)=a iff eta. (eval,,) We can now extend the domain of to admit functions such as division, by allowing 6 to return an expression that raises an exception:* 6: Const x ClosedVal— ClosedVal v {exception x in raise xv | vis closed}. Functions such as division can now be defined on every element of their input type, by returning an exception when their application does not make sense. * Usually a set of exceptions that may be raised by constant functions is defined in an initial environment; we take an alternative approach to simplify the presentation, SYNTACTIC TYPE SOUNDNESS eg 5.2.2. Typing We extend the set of types with an additional type constructor: tLe bt ba ty >t | cexn The type t exn is the type of exceptions with a parameter of type t, In typing exceptions in the presence of polymorphism, one encounters similar difficulties as in typing references. The phrase raise e,e) requires e, to be an exception of type texn, and e, to be a matching parameter of type t. If e, has type’, the phrase e, handle e,e, requires e, to be an exception of type texn, and e; to be a handler for such exceptions. The handler must be a function of type t->1’, since it takes the exception parameter as input, and returns a value to be returned in place of the value of e;. The obvious typing for exceptions allows the parameter types of exceptions to be fully polymorphic, permitting the following expression to be typed:? let h be exception x in pair (raise x)(ia.b.(a 3) handle x b) in (snd h)(Ad.(fst h) true)(Ay.+1 y) —» exception x in +1 true Here, functions to raise and handle the same x-exception are returned as a pair, bound by a let-expression to h, and then used. In the body of the let-expression, the expression (raise x) has type 2,4, and (Ja.ib.(a 3) handle xb) has type (int—+a3)— (a, %;)—>a3. If the exception parameter type a, is generalized, then in the body of the let- expression an x-exception may be raised with an argument of type bool by (fst h), and caught by (snd h), which is expecting an argument of type int. Since the problems of typing exceptions and references are similar, it is not surprising that the same modifications to the typing rules for functional expressions apply: types and type variables are classified as imperative or applicative, and the let rule is split according to whether the bound expres- sion is expansive (see Fig. 3). Figure 5 presents the additional typing rules for exceptions. Again, as with Reference ML, we require the additional restriction that there be no constants of exception type (t exn). 5.2.3. Type Soundness for Exceptions To establish soundness for the exception typing, we proceed as for references: we establish type preservation for vx, and show that the faulty expressions of Exception ML are untypable. ° The constants pair, fst, and snd provide pairing and projection operations. 8 WRIGHT AND FELLEISEN Pe raise: 7 ern 1) > (raise) Peecn eer (handle) Poe handle: 7 ezn — (tr) + 7) + 2 Ula) n= 11 e2n)...[2n re Te eznoe:r ris imperative 1*e,:t. Proof, The cases for the reductions of vy are the same as before. Case Ufraise xv] — raise xv. From Pe U[raise xv] :t Te raisexv:t’ by app. Hence Po raise x:t, +t (27) and Poe;t, (28) by app. From (27) Pox: tyexn by app and raise, [> raise x:t, +t by app and raise, Pe raisexu:t by app with (28). Case exception y, in exception z, in e— exception x, x; ine. Similar tO Pmerge in Lemma 5.2. Case X[exception 7 ine] —> exception xin X[e]. Similar to pay in Lemma 5.2. Case v, handle xv: —> v,. Mev, :t from Pov, handle xv): by handle and app. Case (raise x v,) handle x v,—+ v,0,. From Ie (raise x v,) handle xv: by handle, app, and Pevit and Pevit ot where x=’ exn. Then [e020 :t by app. SYNTACTIC TYPE SOUNDNESS 79 Case exception zx, x, in exception zx, x, in X[(raise x,r,) handle x,v:] — X[raise x,v)] Then I’ > (raise x,0,) handle x20, 27 I’ (raise x,v,) handle : 1, exn>(t,>1')+1' by app, [> raise x,v, :1' by handle, > exception zx; x, in X[raise x,v,}:t by Replacement * With the extension of the various lemmas, the proof of type preservation for Exception ML is complete. The lemmas go through with simple adaptations to the new syntax. 9 There are several new kinds of faulty expressions for Exception ML. Derinition 5.9 (Faulty Expressions). The faulty expressions of Excep- tion ML are those expressions containing a subexpression of the form: (cv) where 5(c, v) is undefined, (raise v) where v¢ Var, (e handle v) where v ¢ Var, or exception zx in CLx 0], where Cu=[]1CeleC|let xbe Cine|letxbeein | Ax.C | exception x in C | C handle. Again, a uniform evaluation lemma can be shown, and the faulty expres- sions can be proven untypable. Type soundness for Exception ML follows as before. TuroREM 5.10 (Syntactic Soundness for Exception ML). If &*e:t then either ef} or eV» a and > a:t. 5.3. Core ML We can combine references and exceptions in one language, Core ML, that has all the essential features of STANDARD ML. In combining the 80 WRIGHT AND FELLEISEN reference and exception extensions, we must ensure that they interact appropriately. 5.3.1. Semantics To combine the calculi for the two extensions, the R contexts of the reference fragment must be extended to include phrases from the exception fragment; likewise, ¥ contexts must be extended to include phrases from the reference fragment: R Xx «| Rhandle v,v, | pO.X. The phrase exception x in R is not included in R in order that exceptions in the store do not escape their bindings, ic, exception-expressions can move through p-expressions by the exm, reduction, with appropriate variable renaming, p9.exception zx in e—+ exception zx in pbc, but not vice versa, exception zx in p0¢r, x).e—+ p0.CLe handle x), where =[]|CeleC|letx be Cine|letxbecinC|ix.C | p0.C | p8.e | exception x in C| C handle. Type soundness follows from subject reduction, uniform evaluation, and faulty expressions being untypable, as before. THEOREM 5.12 (Syntactic Soundness for CoreML). If &'*e:t then either eft or eR» a and > a:t. 6. Control ML In this section we present an extension to Functional ML providing first- class continuations. The typing of our extension is similar to that described by Duba er al. [8], and implemented in StaNDARD ML oF New Jersey [34]. It is a simple matter to merge this extension with Core ML. Control ML extends Functional ML’s syntax with two new constructs: leve,|letxbee,ine,|aborte (Expressions) c|x|¥ | Axe | callec. (Values) 82 WRIGHT AND FELLEISEN An abort-expression evaluates its subexpression to a value, and returns this value as the result of the program. When the callec operator (call- with-current-continuation) is applied to a function f, it captures a represen- tation of the current continuation (or program control stack), encapsulates this continuation in an abstraction, and applies f to this abstraction. If this abstraction is later applied to a value, control transfers to the captured continuation. 6.1. Semantics While defining calculus reductions for first-class continuations is possible [13, 14], the resulting calculus is inappropriate for our problem Since we are only interested in evaluation, we take a simpler approach [11]. We give top-level evaluation rules, program reductions, for the control operators by extending the stepping relation (1 ) directh Efe} Efe] if ere’ (5, B,, fet, Y) Efeallce v > E[v(ix.abort ELx))) {callec) Elabort e]re (abort) where []|E£e|v£|letxbe Eine. In this style of semantics, the evaluation context £ represents the current continuation. An abort reduction simply discards the current continuation, continuing evaluation with its subexpression. The callee reduction captures the current continuation, encapsulates it in a function, and applies callce’s argument to this function. The continuations created by callec are abor- tive: when invoked, they discard the continuation surrounding their application (via an abort reduction), installing instead the captured continuation. Answers are simply values, and eval is defined as for Functional ML. Figure 6 illustrates a simple use of callcc. This program computes the product of a list of numbers, performing no multiplications if the answer is let product be Ax. callec (Ak. letrec p be Az. if nil? z then 1 else if = 0 (car z) then k 0 else * (car z) (p (cdr z)) in p x) in product (cons 2 (cons 3 (cons 0 (cons 5 nil})}) Fic. 6, A program illustrating a simple use of eallec. SYNTACTIC TYPE SOUNDNESS 83 zero, The constants nil, cons, nil?, car, and edr are the usual constants and operations for lists, The expressions if...then...else... and letrec...be...in...are syntactic sugar for appropriate constant applica- tions. This program computes the product of a list of numbers, performing no multiplications if the answer is zero. The program escapes from pending multiplications by jumping out of the recursion to the continuation of the application of product. 6.2. Typing The obvious approach to typing callec leads to the following rule: Pe calles : ((t, +13) + 15) +5. (naive-callee) As indicated by the callec reduction, callec takes a function whose argu- ment is a procedural abstraction of the evaluation context, the continuation. If the evaluation context expects a value of type t,, then the continuation has typet,+t, for any typet,. If callec’s argument ignores this continuation, it must produce a value of type t,, which implies that callcc’s argument must have type (t,-+ 12) t,. The result type of the continuation, 12, is arbitrary, because the application of k built into the continuation ensures that it never returns. However, this obvious typing is unsound, as illustrated by the following example:'° let x be callec (Ak. pair(4x.x)(4f. k(pair f(4d.5)))) in (Jz.snd x(Ax. +x 1))(fst x true). The callec application returns a pair of type (a+) ((«— a) — int), consisting of the identity function and a function that applies a continu: tion. Since x is not free in the type environment, it is closed over, and x has type scheme Wa. (> x) x ((a + 2) > int) in the body of the let-expression. In evaluating the body, fst x is the polymorphic identity function, so it may validly be applied to true. Then the second function of the pair is applied to (4x.+%1), and the continuation so invoked rebinds x to the pair consisting of (4x.+x1) and (2d.5). The second evaluation of fst x true results in an attempt to add 1 to true. As with references and exceptions, a correct typing for continuations builds upon the classification of types as imperative or applicative, and requires the let typing rules of Fig. 3. The correct typing rules are: "© A variation of this example was discovered by Robert Harper and Mark Lillibridge (sm electronic mailing list, July 8, 1991). Despite widespread use of a naively typed callec extension in STANDARD ML OF NeW JERSEY, it took two years until this problem was discovered. 84 WRIGHT AND FELLEISEN Pe eallee :((t;+7,)>1,) >t, if t, isimperative (calle) Pee:t Te aborte:t, (abort) An abort-expression may have any type, regardless of the type of its subexpression, because when evaluated it never returns. 6.3. Weak Type Soundness Because abort-expressions can return a value of any type, proving type soundness for the continuation extension is not as simple as for the previous extensions. For example, if ¢ is an expression of type bool, the program if c then 1 else (abort true) is typable according to the above typing rules, but returns either int or bool according to whether ¢ is true or false, Thus subject reduction in the usual sense does not hold; however, a weaker lemma does hold, stating that typability is preserved. MAIN Lemma 6.1 (Typability Preservation). If e,:1 and e,+-»e, then & e,:'. Proof. We need only consider the additional cases for the the callcc and abort reductions. The others are simply adapted from Lemma 4,3 (Subject Reduction for Functional ML). Case Elaborte]+—>e. Then [oe:t’ for some 7’. But since Elabort e] is closed and E does not bind variables, e is closed, hence met Case Elcallce v] > E[v(4x.abort ELx])]. From © £[callec ve]: we have > calle v:1,, and by callee and app Seton) ot (29) where t, is imperative. Since E is closed, x does not appear in £, and we claim that [x+ t,] = E[x]: 1. The proof of this claim proceeds by induction on the structure of E. Case E=( }. Then t=1,, and [xror,J> x: by var. Case E=(E’e’), Then & (E'[eallec ve’): t, and by app > E'[eallec v} : 1341 (30) and Se'tty (31) SYNTACTIC TYPE SOUNDNESS 85 for some t;. Then [x++t,]& E’[x]:t,->+ by ind. hyp. with (30), Also [ret] e': 1, by Lemma 4.1* with (31) since x¢ FV(E). Hence Leg] EL by app. Case E=(v E'), Similar to the previous case. Case E=\et x' be E’ in e’. Then > let x’ be E'[callecv] in Since (callec v) is expansive, £’[callee v] is expansive, Thus by let, > E'[eallee v)} : 13 (32) and — [x'++ AppClose(ts, @)]>e':t (33) for some 13. Then [xH1,J>£'Lx]:t, _ by ind. hyp. with (32), (34) and [x' H+ AppClose(t;, B)ILx 11] > e' by Lemma 4.1* with (33) ie, [ere ty ]Lx’H+ AppClose(ts, Bee’ :t. By the critical restriction that t, is imperative, AppClose(ts, 2) = AppClose(ts, [x++t1]), hence Ler ry ]Lx' > AppClose(ts, [x 1, ]))] > ert Lxr41,]> let x’ be E'[x]ine’:t by let, with (34). This completes the proof of the claim. Hence [xtH+1,]& abort E[x]:t; by abort, & (Ax.abort E[x]):1; 1, _ by abs, > v(Ax.abort ELx]) : 1, by app with (29) > E[v(dx.abort E[x])]:t by Replacement*. The faulty expressions for Control ML are the same as those of Functional ML, extended to the new syntax. DeFINITION 6.2 (Faulty Expressions). The faulty expressions of Control ML are the expressions containing a subexpression (cv) where 4(c, v) is undefined. 86 WRIGHT AND FELLEISEN, As with Functional ML, the faulty expressions are untypable and Uniform Evaluation holds. However, since we only have typability preser- vation, we obtain a weaker version of syntactic soundness that does not indicate the type of answers. TuroreM 6.3 (Weak Syntactic Soundness). If & 1 then either ef} or err. Proof. By Uniform Evaluation, either e+» e’ and e’ is faulty, or eft, or e+» 0, Since e:r, Typability Preservation implies =v: tr’ and = e':t’. Suppose e+» e” and e’ is faulty. Since faulty expressions are untypable, e':1’ is a contradiction, therefore this case cannot occur. Hence either eff orer—e. This weaker theorem establishes weak soundness, but does not imply strong soundness. In fact, if the use of abort is unrestricted, it is not possible to predict the type of an answer, as the example at the beginning of this section illustrates. 6.4. Strong Type Soundness Examining the proof of Typability Preservation reveals that every reduc- tion with the exception of abort preserves type. In particular, the callec reduction preserves type, which suggests that calle by itself is strongly sound. To obtain a proof of strong soundness for callec, we must eliminate abort from the surface language available to programmers, but retain it in the underlying language of evaluation for callec reductions. Because the abort expressions introduced by callec applications have a restricted shape, they never return values of other than the top-level type of the program, and do not compromise strong soundness. To establish a subject reduction lemma, we define an augmented type system that infers both the ordinary type of an expression and a set of abort types. The abort types of an expressione are the types of the immediate subexpressions of abort-expressions in e. The augmented system requires abort-expressions to be monomorphic to ensure that each syntactic occurrence of abort can produce only one type of answer. This restriction eliminates expressions such as the following: let a be 4x. abort x in ifethena1 else a true SYNTACTIC TYPE SOUNDNESS 87 Petern? if M2)>r (var) PoterrD if TypeOf(e)> 7 (const) PeYi(non)on oni? ~) Tem note Po Arern 1.7 (abs) m1 %2,T Petes: 1,7 (app) Toe eit? aa Piz r+ Close(r can Po* let z be vine: t, Pet ein,T Piz es AppClose(r,, FT) &* 2: 72,7 _e ¢ Values (let.) Tet let z beer inex: tT . Pe callec: ((r) + 7) 11) = ri, if 7 is imperative (calle) Preterm? net (abort) Te abort e: 72.7 Close(r,P,T) = Var...an-7 where {ai,--.,an} = FTV(r)\(FTV(L)U FTV(T)) AppClose(t,P,T) = Vay ...0q-7 where {ary--.,@n} = (FTV(r)\ (FTV(L)U FTV(T))) 9 AppType Var Fic. 7. The augmented type system for Control ML. Hence if a well-typed program aborts, the answer produced is one of the program's abort types. Type judgments for this augmented system have the form '>*e:1, T, meaning that in type environment 7, expression ¢ has ordinary type and abort types 7, where T is a set of types. Figure 7 presents the typing rules of the augmented system. The augmented type system corresponds closely to our original type system for Control ML. The rule for typing abort-expressions is the only rule that connects the ordinary type and the abort types of an expression. In each axiom (var, const, Y, callec) the abort set is completely unconstrained; the inference rules simply propagate the abort set. The let- expression rules do not generalize type variables in the set of abort types, hence the augmented system does not permit polymorphic uses of abort, and accepts a subset of the expressions accepted by the ordinary system. A Correspondence Lemma establishes this connection between the ordinary system ( ) and the augmented system (>). LemMa 6.4 (Correspondence). (i) If [e:t and e contains no abort-expressions then >“ e: t, T for any T; (ii) If Pe*e:t, T then Pert. engine 88 WRIGHT AND FELLI N Proof. The proof of each direction shows how to construct a deduction for the consequent from a deduction of the antecedent. Both proofs are straightforward. Subject Reduction for the augmented system establishes that reduction preserves the set of abort types. As the callcc reduction introduces an abort-expression with the top-level type of the program, the set of abort types preserved by Subject reduction includes the top-level type. MAIN Lemma 6.5 (Subject Reduction). If &e,:1,T and teT and ete, then >“e,:0', Tand VET. Proof. The proof proceeds by case analysis according to the reduction e;e;. Each case is easily adapted from the corresponding case in the proof of Typability Preservation with straightforward adaptations of the necessary lemmas. With Uniform Evaluation and the fact that faulty expressions are untypable (in the ordinary system), we obtain a syntactic soundness theorem for abort-free expressions, THEOREM 6.6 (Syntactic Soundness). Jf e:t and e contains no abort-expressions then either ef or er—»v and mvt. Proof. By Uniform Evaluation, either e-—» e’ and e’ is faulty, or ef}, or et—»v, Since Se:1 and e contains no abort-expressions, by Corre- spondence =“e:t, {x}. Subject Reduction then implies =e, {r} Similarly &“v:t, {t}, and by Correspondence Se’: and S0:t. Suppose er—»e’ and e’ is faulty. Since faulty expressions are untypable, © e': risa contradicton, therefore this case cannot occur. Hence either ef orerevand ou:t. 7. Discussion Subject reduction is the key lemma in our approach to proving type soundness. In order to demonstrate subject reduction, it must be possible to assign a type to each intermediate evaluation state of a program. This is most easily accomplished by specifying evaluation as rewriting. Rewriting may be specified as local reductions, as our calculus for Core ML, or as program (or top-level) rewriting, as in Control ML. Through most of this paper, we present the semantics of the various languages with calculi that permit local reductions. It is also possible to use our proof technique with a semantics that specifies only program reduc- tions (++), as in Control ML. Such a semantics for Reference ML is SYNTACTIC TYPE SOUNDNESS 89 slightly simpler, as the ref, Pmerges ANd yy, teductions coalesce into one program reduction, but the structure of the proof is essentially the same. Our work on an alternative type system for references uses this approach [38]. We chose to use calculi in this paper as the resulting proofs are more regular in structure. In specifying the semantics of references as a calculus, we use an addi- tional expression form, the p-expression, that is not present in ML. As noted earlier, p-expressions may be regarded as an abbrevations, both from a semantic perspective and a typing perspective (the typing rule for p-expressions can be derived from the abbreviation), In principle, it is possible to eliminate p-expressions from the syntax, however the specifica- tion of redexes in the reduction rules becomes complicated. Alternatively, p-expressions may be considered as belonging to the state space of evalua- tion, and not to the language of programs that may be written by a programmer. In a presentation of the typing rules for consumption by programmers, the typing rule for p-expressions may be deleted. However, unlike p-expressions, the abort-expressions of the continuation fragment cannot be considered as abbreviations [10]. To obtain a strong soundness theorem, abort-expressions must be considered as belonging only to the evaluation space, and not to the syntax of programs. The exception fragment has no such additional expressions. Other operational or denotational techniques for specifying semantics introduce additional semantic objects, such as closures and stores, rather than additional expression forms. Since the type system does not apply to such objects, stating and proving strong type soundness requires introduc- ing a semantic relation () between semantic objects and types (see Section 2). We believe that introducing additional expression forms and typing rules is the simpler choice, and offer the simpler proofs produced by our method as evidence. While in this paper we have concentrated on the essential aspects of ML, there are other features of static type systems that we believe our technique can address. STANDARD ML contains a datatype specification mechanism that allows the definition of new types and associated data constructors. This mechanism is indispensable when writing non-trivial ML programs. Subtyping, inheritance, and type inference for records are a strong focus of recent research efforts to explain object-oriented languages, as many popular object-oriented languages have unsound static type systems. Reppy [29] has successfully addressed concurrency with our technique; it should also be possible to treat nondeterminism and distributed computing. We have used our technique to prove an alternative type system for references sound [38]. Finally, it may be possible to adapt our technique to demonstrate the consistency of module systems like that of STANDARD ML. ei) WRIGHT AND FELLEISEN, APPENDIX: Tue Core oF STANDARD ML. Syntax. ex=v|e,e,| let x bee, ine, | p6.e | exception xine c|x1¥|Axe|ref|!|:= | raise |e handle | :=v| raise v|e handler Ou={}* sx {exception zx in} {p#.} »| {exception zx in} {p0.} raise xv Semantics. eval(e)=a iff er—wa Ele]-E[e'] iff ere’ Ex=[]|E£e|v£|let x be Zine | Ehandle v,»; | 0. | exception z in E Functional ML cv— (c,v) if 5(c, v) is defined ) (Ax.e)v—> e[xrov] (B) let x be vine— e[xrrv] (let) Yo— v(ax.(Yv)x) wy References ref v— p(x, v).x (ref) pOXx,v>.REE x] — pO.REv] (deref) pOKx, vy >. RE = x02] —> pO p80, 82.¢ (Perse) R[p8.e]— p@.Rle] if R#C] (Pun) Ru=[J|Re|vR| let be Rine| Rhandle v,v, Exceptions U[raise xv] raisexv if U4] (raise) (raise x v,) handle x v,—> v20, (handle) SYNTACTIC TYPE SOUNDNESS 91 exception yx,x2 in exception yx,x2 in (reraise) X{(raise x,v,)handle x,0,) —* X{raise x,v,] MF v, handle x v,— v, (unhandle) exception y, in exception 7, ine —+ exception y, 7; ine (XM merge) X[exception x ine] — exception xin X[e] if X¥#[] (exmyn) Us=[]| Vel vu |letxbe Vine Xu=[][Ne|pX|letx be Xine| Xhandle o,0> | p0.X Typing. Functional ML Tox:t if Mx)y>t (var) Tee:t if TypeOf(c)>t (const) FeV an) nen)osh ) Ue nec (abs) Te Axe :t) >t Peeiten feet om Haceieise ieee tila ee close(ey, 11 eet (let) To letxbevine:t, Poet, Px AppClose(t,,P)]ee::t, ey ¢ Values te, Te let x bee, ine, ine,:t Close(t, P) = Wat, .%q.T Where {255 ny Eq} = FTV t)\FTVIL), (FTV(t)\FTV(L)) 0 AppTypeVar AppClose(t, P) = Wa, -.t,.t where {4, « References Peref:t—+tref if cisimperative (ref) Po litrefor (deref) Po =i (tref+t +t) (assign) TEx Hoty ref Jun [xq te ref est PU xp rr ty ref Jon Dx,r> tere] v.21, tisimperative 1 0 Teeits Teehandle:t, exn (t,t) >t (bandle| FLxirosiexm].[x,ne tae] e:t cyisimperative ISIS" gg) T= exception x,. pine:t ACKNOWLEDGMENTS We thank Bob Harper for pointing out that type preservation is known as subject reduction in combinatory logic, and Hans Boehm and the anonymous referees for comments on earlier drafts of this paper. Recetvep May 6, 1991; FINAL MANUSCRIPT RECEIVED July 6, 1992 REFERENCES: 1. ABADI, M., CARDELLI, L., PIERCE, B., AND PLOTKIN, G. (1991), Dynamic typing in a stati- cally-typed language, in “ACM Transactions on Programming Languages and Systems 13,” Vol. 2, pp. 237-268. Previously appeared in “Proceedings of the 16th Annual ‘Symposium on Principles of Programming Languages,” pp. 213-227 (1989). Barenprect, H. P. (1984), “The Lambda Calculus: Its Syntax and Semantics,” revised ed. Studies in Logic and the Foundations of Mathematics, Vol. 103, North-Holland, ‘Amsterdam. 3. CRANK, E., AND FELLEISEN, M. (1991), Parameter-passing and the lambda calculus, in “Proceedings of the 18th Annual Symposium on Principles of Programming Languages,” pp. 233-244 4, Curry, H. B, anp Feys, R. (1958), “Combinatory Logic,” Vol. I, North-Holland, Amsterdam, 5. Damas, L., AND MILNER, R. (1982), Principal type schemes for functional programs, in “Proceedings of the 9th Annual Symposium on Principles of Programming Languages,” pp. 207-212 6. Damas, L. M. M. (1985), “Type Assignment in Programming Languages,” Ph.D. thesis, University of Edinburgh. 7. DONAHUE, J., AND DEMERS, A. (1985), Data types are values, ACM Trans. Programming Languages Systems 7, No. 3, 426-445. 8. Duna, B. F., HARPER, R., AND MacQuezy, D. (1991), Typing first-class continuations in ML, in “Proceedings of the 18th Annual Symposium on Principles of Programming Languages,” pp. 163-173. 9. FELiztsen, M. (1988), The theory and practice of first-class prompts, in “Proceedings of the 15th Annual Symposium on Principles of Programming Languages,” pp. 180-190. 10. FeLLEiseN, M. (1991), On the expressive power of programming languages, Sei, Comput Programming 17, 35-15; preliminary version in “Proceedings of the European Symposium on Programming,” Lecture Notes on Computer Science, Vol. 432, Springer-Verlag, Berlin/ New York (1990). a. 15, 16, 1. 18, SYNTACTIC TYPE SOUNDNESS 93 FELLEISEX, M., AND FRIEDMAN, D. P, (1986), Control operators, the SECD-machine, and the J-calculus, in “Formal Description of Programming Concepts III” (M. Wirsing, Ed.), pp. 193-217, Elsevier (North-Holland), Amsterdam. FELiesex, M., AND Frigpmax, D. P. (1989), A syntactic theory of sequential state, Theoret. Comput, Sci. 69, No. 3, 243-287; preliminary version in “Proceedings of the 14th Annual Symposium on Principles of Programming Languages.” pp. 314-325 (1987). FEiuetsen, M., FRIEDMAN, D.P., KoHLBECKER. E. E., ND Duna, B. (1987), A syntactic theory of sequential control, Theores. Comput. Sci. 52, No. 3, 205-237; preliminary version in “Proceedings of the Symposium on Logic in Computer Science,” pp. 131-141 (1986), FELLEISEN, M., AND Hie, R. (1992), The Revised Report on the Syntactic Theories of Sequential Control and State, Theoret. Comput, Sci. 02, 235-271. Hixptey, R, (1969), The principal type-scheme of an object in combinatory logic, Trans. Amer. Math, Soc. 146, 29-60. Hinpity, R. J., aND SELON, J. P. (1986), “Introduction to Combinators and 4-Calculus,” ‘Cambridge Univ. Press, London/New York. Leroy, X., aND Weis, P. (1991), Polymorphic type inference and assignment, in “Proceedings of the 18th Annual Symposium on Principles of Programming Languages, pp. 291-302. MacQueen, D. B., PLOTKIN, G., AND Seti, R. (1984), An ideal model for recursive polymorphic types, in “Proceedings of the 11th Annual Symposium on Principles of Programming Languages,” pp. 165-174. Mason, I., AND Taccorr, €. (1989), Programming, transforming, and proving with func- tion abstractions and memories, in “Proceedings of the International Conference on Automata, Languages, and Programming,” pp. 574-588, Lecture Notes in Computer Science, Vol. 372, Springer-Verlag, Berlin/New York |. Miner, R. (1978), A theory of type polymorphism in programming, J. Comput. System Sci. 17, 348-375, Mixer, R., AND ToFTE, M. (1991), Co-induction in relational semantics, Theoret. Comput. Sct. 87, 209-220. Mixer, R., axp Torte, M. (1991), “Commentary on Standard ML.” MIT Press, ‘Cambridge, MA. Mutyex, R., ToFTe, M., aNb Harper, R. (1990), “The Definition of Standard ML,” MIT Press, Cambridge, MA. Marcie. J. C., aNb HARPER, R, (1988), The essence of ML, in “Proceedings of the 15th Annual Symposium on Principles of Programming Languages,” pp. 28-46. MiTcHELL, J. C., AND PLOTKIN, G. D. (1988), Abstract types have existential type, ACM Trans. Programming Languages Systems 10, No.3, 470-502. Also appeared in “Proceedings of the 11th Annual Symposium on Principles of Programming Languages,” pp. 37-51 (1984). Piorein, G. D, (1975), Call-by-name, call-by-value and the lambda-caiculus, Theoret Comput, Sci. 1, 125-159, PvotkiN, G. D. (1981), i “A structural approach to operational semantics,” Technical Report, DAIMI FN-19, Arhus University. Ress, J., AND CLINGER, W. (1986), Revised? report on the algorithmic language Scheme, SIGPLAN Not. 21, No. 12, 37-19. Reppy, J. H. (1991), “Higher-Order Concurrency, Ph. D. Thesis, Cornell University. ReynoLos, J. (1972), Definitional interpreters for higher order programming languages, in "ACM Conference Proceedings.” pp. 717-740. Reynoups, J. C. (1974), On the relation between direct and continuation semantics, in “Proceedings of the International Conference on Automata, Languages, and Programming,” pp. 141-156. 94 WRIGHT AND FELLEISEN 32. Scorr, D. (1976), Data types as lattices, STAM J. Comput. 3, No. 5, 522-S86. 33. SexpIy, J. P. (1977), A sequent calculus for type assignment, J. Symbolic Logic 42, 11-28 34. STANDARD ML or New Jersey (1991), Release notes (version 0.75), AT&T Bell Laboratories. 35. TaLPIN, J.-P., AND Jouvetor, P. (1991), “The Type and Effect Discipline,” Technical Report EMP-CRI A/206, Ecole des Mines de Paris. 36. TorTE, M. (1987), “Operational Semantics and Polymorphic Type Inference,” Ph.D. Thesis, University of Edinburgh. 37. Torte, M. (1990), Type inference for polymorphic references, Inform. Comput. 89, 1-34. 38. WrichT, A. K. (1992), Typing references by effect inference, in “Proceedings of the European Symposium on Programming,” pp.473-491, Lecture Notes in Computer Science, Vol. $82, Springer-Verlag, Berlin/New York.

Вам также может понравиться