Subtyping Union Types J’er“ome Vouillon CNRS and Universit’e Paris 7 Case 7014, 2 Place Jussieu, 75251 Paris Cedex 05, France Jerome.Vouillon@pps.jussieu.fr Abstract. Subtyping of union types can be fairly complex due to inter­ actions with function and pair types. Furthermore, this interaction turns out to depend on the calculus considered: for instance, a call­by­value calculus and a call­by­name calculus will have di#erent possible subtyp­ ing rules. In order to abstract ourselves away from this dependence, we consider a fairly large family of calculi. We define types in a semantic fashion, as sets of terms. Then, a type can be a subtype of another type if its denotation is included in the denotation of the other type. Using inference rules, we specify a subtyping relation which is both sound and complete with respect to the family of calculi. We expect this framework to allow the study of subtyping relations that only hold for some classes of calculi by restricting the family considered, and to allow the study of subtyping relations for richer type systems by enriching the family. Key words: union types, subtyping, semantics, lambda­calculus. 1 Introduction The design of a subtyping relation for a language with a rich type system is hard. The subtyping relation should satisfy conflicting requirements. On the one hand, one would like the relation to have strong theorical fundations, rather than being defined in an ad hoc, purely algorithmic, fashion. It is therefore tempting to base it on the semantics of the language. But, on the other hand, one should be careful not to tie it too tightly to a particular language. Especially, one should avoid accidental special cases which happen to hold only in the language considered. Indeed, the relation should be robust in order to accomodate future language extensions. It should also be simple enough so that the users can understand it, and should possess good algorithmic properties: checking whether two types are in a subtyping relation should be reasonably simple and e#cient. We should emphasize the fact that the possible subtyping relations depend on the language considered by providing some examples. Let us first provide some rough intuition about types. We take the view that well­typed terms may diverge but will evaluate without error. A term of type # is a term that always diverges. A term of type # evaluates without error. A term of type # # # # behaves like a term of type # once applied to a term of type # # . A term of type # ## # behaves as a term of type either # or # # . We write # <: # # to mean that # is a subtype of # # and # = # # to mean that # and # # are equivalent, that is, subtype of one another. We can now present some typing relations that only hold under some conditions on the calculus. -- In a call­by­value language, we can have # <: # # #. Indeed, suppose we take a term e of type #. When we apply it to a term e # of type # (that is a term whose evaluation does not terminate), we get a term e e # whose evaluation does not terminate. So, the term e has type # # #. -- In a call­by­name language, we can have # <: # # # (as in Pierce's thesis [1, p. 20]). Indeed, as argued by Dami [2], in a call­by­name language, it makes sense to consider # as the set of all terms. Then, types need to be interpreted in a slightly unusual way. A well­typed terms does not necessarily evaluate without error. Rather, only terms whose type # is not equivalent to # have these properties. Then, if we apply a term of type # to another term of type #, we get a term of type #, which corresponds to the subtyping assertion # <: # # #. -- In a call­by­value language, we can have the distributivity law (# 1 ## 2 )×# = (# 1 ×#)#(# 2 ×# ). This law does not hold in a call­by­name language with non­ determinism. Indeed, a term of type (# 1 # # 2 ) × # may well be a pair whose first component evaluates sometimes to a value of type # 1 and sometimes to a value of type # 2 . Still, it holds in a call­by­need language with non­ determinism, as an expression is then evaluated at most once. -- In a deterministic calculus, union of function types # # # # obey very special subtyping rules when # is finite (as observed by Damm [3]). The reason is that these types are isomorphic to tuple types. On the other hand, some rules seem very robust: -- The arrow is covariant on the left and contravariant on the right: if # 1 <: # # 1 and # # 2 <: # 2 , then # 2 # # 1 <: # # 2 # # # 1 ; -- Union types are least upper bounds: if # <: # 1 or # <: # 2 , then # <: # 1 # # 2 ; if # 1 <: # and # 2 <: # , then # 1 # # 2 <: # . The aim of this paper is to develop a framework in which we can substantiate the above claims, and thus understand which subtyping assertions # <: # # hold ``by accident'' (depending on some specific properties of a language), and which are more universal (valid for a large family of calculi). Rather than choosing a particular calculus, we specify a broad family of calculi in a fairly abstract way. For each calculus, we interpret a type # as a set of terms ###. Given a subtyping relation <:, defined for instance by inference rules, we can state that a subtyping assertion # <: # # is valid when ### # ## # #. Then, a subtyping relation is sound when any derivable subtyping assertion is valid in all calculi. It is complete when every universally valid assertion can be derived. We present a relation which is both sound and complete for the family of calculi considered. Though this is not addressed in this paper, it would then be possible to study relations which are only sound under some assumptions by restricting the family of calculi. The paper is organized as follows. The family of calculi is defined in Sect. 2. A particular instance is given in Sect. 3. We present a simple type system, define a subtyping relation and prove the soundness and completeness of the relation (Sect. 4). We conclude by presenting related work (Sect. 5) and directions for future work (Sect. 6). Most proofs are omitted for lack of space. They are available online 1 in an extended version of the paper [4]. 2 A Family of Abstract Calculi 2.1 Informal Presentation and Definitions We would like to study subtyping for a family of calculi with functions, pairs and constants. The first step is to associate to each type # its semantics ###, that is, the set of terms of type # . We type terms rather than values, because the notion of terms is more fundamental: the notion of value depends on the language considered. Besides, it is not always possible to reduce the behavior of a term to the behavior of a set of values, especially in call­by­name calculi. This is actually possible in the calculus of Sect. 3, but only because we made some specific choices about types. As it turns out, it is convenient to only consider sets of terms that satisfies a given closure property: the closure E of a set of terms E is the set of terms that cannot be distinguished from the terms in E. Notice that the choice of a closure operator is not neutral. It dictates what can be observed about terms. Types categorize terms according to their behavior. We should be able to use them to avoid some unsafe behavior, typically runtime errors. So, we distinguish a set S of safe terms. Dually, we define a set N of neutral terms (typically, terms that loop) as the intersection of all non­empty closed terms. We call semantic type a closed set of terms included in S and including N. We require the semantics ### of a syntactic type # to be a semantic type. For the sake of flexibility, we don't assume S #= T nor N #= #. In particular, we can take S = T if we want to interpret the type # as the set of all terms. Let us now sketch how we define the semantics of types. The idea is that we want to be able to build more complex typed terms by assembling smaller typed terms according to simple (typing) rules. For instance: App e : # # # # e # : # # e e # : # Fst e : # × # # fst e : # Snd e : # × # # snd e : # # The rules above suggest the following inclusions. ## # # ## # {e # S | #e # # ## # #.e e # # ###} ## × # # # # {e # S | fst e # ### # snd e # ## # #} These inclusions ensure the soundness of the typing rules. In order to reason about types, it is important to have a more precise characterization of their 1 http://www.pps.jussieu.fr/~vouillon/publi/#union semantics. It seems therefore natural to replace these inclusions by an equality. ## # # ## = {e # S | #e # # ## # #.e e # # ###} ## × # # # = {e # S | fst e # ### # snd e # ## # #} But the sets ## # # ## and ## ×# # # must be semantic types. The definitions above clearly ensure that these sets are included in S. They must also be closed and must contain N. We cannot force this by making the sets larger, as this would violate the soundness conditions. Instead, we make more assumptions on the calculi. We say that a function is continuous when the inverse image of a closed set is closed, that a function is strict when the inverse image of N is included in N. We can prove inductively that the sets ## # # ## and ## × # # # are closed if S is closed and the functions fst, snd, and e ## e e # (for all terms e # in S) are continuous. Similarly, we can prove that these sets contain N if N # S and the same functions are strict. This appears more clearly if the equations above are rewritten in a more algebraic form. ## # # ## = S # # e # ### # # {e | e e # # ###} ## × # # # = S # fst -1 (###) # snd -1 (## # #) It is really natural for all these functions to be strict. The continuity proper­ ties may seem harder to achieve. We will see in Sect. 3.2, that it is actually straightforward to define a closure operator ensuring these properties. The calculi also have constants, denoted #. These constants are assumed to be safe. We define a singleton type # for each constant #. Its semantics is the least closed set of term containing the constant #: ### = {#} . 2.2 Formal Specification The family of calculi we consider are the calculi to which we can associate: -- a set of terms T; -- a closure operator E ## E on terms; -- a closed subset S # T of safe terms; -- three operators: app : T # T # T e ## e # ## e e # fst : T # T e ## fst e snd : T # T e ## snd e such that e ## e e # (where e # # S), fst and snd are continuous and strict; -- a set of constants # # S. 2.3 Semantic Operations We define one operation on set of terms for each type construction we have in mind: bottom type, union of two types, function types, pair types and constant types. Note that the semantic union # of two sets of terms is not simply their union. Indeed, there may be some terms that are in neither of the sets but cannot be distinguished from the terms in the union of both sets. These operations are used to define the semantics of types in a straigtforward fashion in Sect. 4.1. # = N E # E # = E # E # E # # E = {e # S | #e # # E # .e e # # E} E × E # = {e # S | fst e # E # snd e # E # } # = {#} It is clear that all these operations map semantic types to semantic types. 3 A Concrete Calculus We present a particular instance of the family of calculi considered. This calculus is used in Sect. 4 to prove the completeness of a subtyping relation. It actually turns out to be universal, in the sense that a subtyping relation is complete if and only if it is complete for this particular calculus. 3.1 The Calculus The calculus we consider is a call­by­name calculus with pairs and constants. Its main remarkable characteristics are a notion of errors, a strict let binder and two non­deterministic choice operators. The syntax of the calculus is given by the following grammar: e ::= x variable #x.e abstraction e e application (e, e) pair fst e first projection snd e second projection # constant if e = # then e else e conditional e # e erratic choice e # e error­avoiding choice let x = e in e strict let error error The set of constants # is supposed to be infinite. A bigstep semantics is given in Fig. 1. The values are a subgrammar of terms: v ::= #x.e | (e, e) | # | error In the reduction rules, we write v #= v # where v # describes a specific shape of values (for instance, v # is (e 1 , e 2 )) to mean that v is not of the same shape as v # . Var­Error x # error Abs #x.e # #x.e App e # #x.e1 e1 [e # /x] # v e e # # v App­Error e # v v #= #x.e1 e e # # error Pair (e1 , e2 ) # (e1 , e2 ) Fst e # (e1 , e2 ) e1 # v fst e # v Fst­Error e # v v #= (e1 , e2 ) fst e # error Snd e # (e1 , e2 ) e2 # v snd e # v Snd­Error e # v v #= (e1 , e2 ) snd e # error Constant # # # If­Equal e # # e # # v if e = # then e # else e ## # v If­Not­Equal e # # # # #= # # e ## # v if e = # then e # else e ## # v If­Error e # v v #= # # if e = # then e # else e ## # error Para­Left e # v e # e # # v Para­Right e # # v e # e # # v Catch­Left e # v v #= error e # e # # v Catch­Right e # # v v #= error e # e # # v Catch­Error e # error e # # error e # e # # error Let e # v v #= error e # [v/x] # v # let x = e in e # # v # Let­Error e # error let x = e in e # # error Error error # error Fig. 1. Semantics The semantics is rather standard and unsurprising. We simply say a few words about the two non­deterministic choice operators. The first one e # e # is the standard erratic operator: e # e # # v if and only if either e # v or e # v. The second one e # e # is a bit like an angelic choice operator, but instead of attempting to avoid non­termination, it attempts to avoid errors. Another way of understanding this operator is to consider it as a symmetric variant of a catch operator: it evaluates one of the terms e or e # and, if this fails, falls back to evaluating the other term. The unusual notations emphasize the fact that both operations correspond to a least upper bound, as we will see in Sect. 3.4. We define the following diverging term: diverge = (#x.x x) (#x.x x) . 3.2 Orthogonality Remember that we need to specify not only a calculus but also a closure operator on sets of terms. We first present a generic way of building a closure operator. The choice of a particular closure operator is made in the next section 3.3. A convenient way to define a closure operator on sets of terms is by orthog­ onality between terms and contexts. At this point, it does not matter what the set of contexts is. We just assume given an orthogonality relation e # c between contexts c and terms e. Its intended meaning is that the term e behaves prop­ erly in the context c. We define the orthogonal of a set of terms E as the set of contexts in which all terms in E behave properly: E # = {c | #e # E.e # c} . Conversely, we define the orthogonal of a set of contexts C as the set of terms that behave properly in all the contexts in C: C # = {e | #c # C.e # c} . These two functions defines a Galois connection between sets of terms and sets of contexts. The important point here is that the composition of these two func­ tions, which associates to a set of terms E its biorthogonal E = E ## , is a closure operator. (Dually, we can define a closure operator which associates to a set of contexts its biorthogonal C = C ## .) Furthermore, we can rely on the following lemma to guide us in the choice of a set of contexts. Let f be a function from terms to terms, and g be a function from contexts to contexts. We say that g is an adjoint of f i# f(e) # c # e # g(c) . Lemma 1. If a function f has an adjoint g, then it is continuous. 3.3 The Closure Operator Using the tools just developped, we can now specify the closure operator. Con­ texts are given by the following grammar: c ::= Id identity c # F frame concatenation c # c join F ::= e fst snd if = # then e else e A context c can be viewed as a stack, with a weird ``stack join'' operation, and F can be viewed as a stack frame. Every context c and term e may be combined to generate a term denoted c e and defined as follows: Id e = e (c # F ) e = c (F [e]) (c # c # ) e = let x = e in ((c x) # (c # x)) where x is fresh . A term e is safe when it does not reduce to the error: S = {e | ¬(e # error)} . The orthogonality relation is defined by: e # c i# c e # S . As indicated in the previous section 3.2, this induces a closure operator on sets of terms. The choice of this operator is crucial: it controls what can be observed by typed terms. We should therefore explain how the contexts are chosen. The identity context Id ensures that S is closed. The frame concatenation operation c#F ensures that each frame is continuous (by Lemma 1). The join operation c#c # allows for disjunctive tests. For instance, the context (Id #fst )#(Id # diverge) will behave properly against terms which reduce to either a pair or a function, but will fail with other terms. This ensures that the closed union E # E # of two semantic types E and E # is not ``too large'' (see Sect. 3.4 for a more precise characterization of this property). 3.4 Properties of the Calculus We study some notable properties of the calculus. The completeness proof will make use of all these properties. Terms and Values. An important property of the calculus is that the behavior of a term (as specificed by the closure operator) is characterized by the behavior of the values it reduces to. Lemma 2 (Terms and Values). A term e is included in a closed set of terms E if and only if any value v it reduces to is included in E. The contexts has been carefully chosen for the lemma 2 to hold. For instance, it does not hold if the syntax of frames is extended with a family of frames e . Indeed, consider the term: f = #x.if # = x then (if # = x then diverge else error) else diverge . We have f # # # S for all constant # # , but f (# # # # ) ## S if the constants # and # # are distinct. So, if Id # (f ) is a context, then we have # # # {Id # (f )} # for all constant # # , but not # # # # # {Id # (f )} # (when the constants # and # # are distinct). Intuitively, the result holds if the evaluation of a term c e first involves the evaluation of the term e. We formalize this property by introducing a notion of linearity: we say that a function f from terms to terms is linear when for any term e and value v, f e # v if and only if there exists a value v # such that e # v # and f v # # v. We then have the expected result. Lemma 3 (Context Linearity). Contexts are linear. Ordering of Terms and Contexts. We define the contextual preorder on terms by e # e # if and only if {e} # {e # }. Likewise, we define a preorder on contexts by c # c # if and only if {c} # # {c # } # . We present the relative ordering of some interesting terms and contexts. This ordering is illustrated below. error e 1 # e 2 e 1 e 2 diverge Id c 1 # c 2 c 1 c 2 Lemma 4 (Least Upper Bounds). For all terms e, e # and for all contexts c, c # , we have: {e # e # } = {e} # {e # }and {c#c # } # = {c} # # {c # } # . As a consequence, the term e # e # is a least upper bound of the two terms e and e # , and the context c # c # is a least upper bound of the two contexts c and c # . Lemma 5 (Divergence). The term diverge is a least term. In particular, diverge # # . Sets of Values. We write V(E) for the set of values contained in a set of terms E: V(E) = {v | v # E}. A direct consequence of Lemma 2 (Terms and Values) is that a closed set of terms is characterized by its values: E = V(E). It seems therefore natural to study some of the properties of the sets of values V(E). Lemma 6 (Least Semantic Type). The least semantic type # = N does not contain any value. As a consequence, it is the least closed set of terms: # = #. Lemma 7 (Union and Values). The values of the closed union of two closed sets is the union of the values of each closed sets: V(E # E # ) = V(E) # V(E # ) Lemma 8 (Prime when Directed). If the set V(E) is directed then the set E is prime, that is, if E # E 1 # E 2 , then either E # E 1 or E # E 2 . Instance of the Family of Calculi. We have the expected result: Lemma 9. The calculus is in instance of the family specified in Sect. 2.2. Orthogonality Functions­Arguments. Just like we defined an orthogonality relation between terms and contexts in Sect. 3.2, we can define a family of orthogonality relations between functions and arguments. In the remainder of this section, we assume given a semantic type E 0 . We define an orthogonality relation between the elements of T (all terms), consid­ ered as function arguments, and the elements of S (safe terms), considered as functions: an argument e # # T is orthogonal to a function e # S when e e # # E 0 . From this relation, we define the orthogonal of a set E of arguments by E fun = {e # S | #e # # E.e e # # E 0 } = E # E 0 and the orthogonal of a set E # S of functions by E arg = {e # | #e # E.e e # # E 0 } . The function E ## E fun arg is a closure on set of arguments. Lemma 10 (Function Orthogonality). The closure induced by function or­ thogonality is strictly finer than the closure induced by context orthogonality: for all set of terms E, we have: E fun arg # E , but the converse inclusion does not always hold. As a consequence, E fun arg = E fun arg = E E fun = E # E 0 E = (E # E 0 ) arg . The key idea to prove the first inclusion is to show that for each context c there is a function #c# that behaves ``similarly''. This function is defined as follows. #c# = #x.let y = c x in diverge It satisfies the following property. Lemma 11 (Context as Function). For any set of terms E and any context c, we have c # E # if and only if #c# # E # E 0 . 4 A Simple Type System We present a simple type system and prove its soundness and completeness. These properties have been mechanically checked using the Coq proof assis­ tant [5]. 4.1 Types The syntax of types is given by the following grammar. # ::= # constructed type # ::= # # # function type # bottom type # × # pair type # # # union type # constant type The semantics ### of a type # is defined inductively on the syntax of types in a straigtforward manner: ## # # # # = ### # ## # # ### = # ## × # # # = ### × ## # # ## # # # # = ### # ## # # ### = # Clearly, the semantics ### of a syntactic type # is a semantic type. 4.2 Subtyping Relation The subtyping relation <: is defined inductively. The subtyping rules are given in Fig. 2 . Note that the rules are syntax­directed, that is, an assertion # <: # # can be derived from at most one rule. Function #1 <: # # 1 # # 2 <: #2 #2 # #1 <: # # 2 # # # 1 Pair #1 <: # # 1 #2 <: # # 2 #1 × #2 <: # # 1 × # # 2 Constant # <: # Bottom # <: # Union­Left # <: # ## # # <: # ## # # # # <: # ## Union­Right­1 # <: # # <: # # # # Union­Right­2 # <: # # # <: # # # # Fig. 2. Subtyping Rules 4.3 Soundness of the Subtyping Relation The soundness of the subtyping relation is straightforward. Theorem 12 (Soundness). If # <: # # , then ### # ## # #. Proof. By induction on a derivation of # <: # # . -- Rule Function: by covariance and contravariance of the operation # . -- Rule Pair: by covariance of the operation × . -- Rule Constant: immediate. -- Rule Bottom: the semantic type # is the least semantic type. -- Rule Union­Left: by induction hypothesis, ###### # # # ## ## #; hence, as ## ## # is closed, ### # ## # # = ### # ## # # # ## ## #. -- Rule Union­Right­1: ### # ### # ## # #. -- Rule Union­Right­2: ## # # # ### # ## # #. ## 4.4 Properties of Constructed Types Before proving the completeness of the subtyping relation <:, we first state some interesting properties of the semantics of constructed types. Lemma 13 (Homogeneity). The set of values V(###) of a constructed type # is homogeneous: V(## # # ##) only contain functions, V(## × # # #) only contain pairs, V(###) only contain the constant #. Lemma 14 (Directed Set). The set of values V(###) is directed. These two lemmas are illustrated below, respectively for function types, pair types and constant types. Values are underlined. The value just above diverge is included in all constructed type of the corresponding kind. Given two values, one of their upper bound is given. #x.(e 1 # e 2 ) (#x.e 1 ) # (#x.e 2 ) #x.e 1 #x.e 2 #x.diverge diverge ((e 1 # e 2 ), (e 1 # e 2 )) (e 1 , e # 1 ) # (e 2 , e # 2 ) (e 1 , e # 1 ) (e 2 , e # 2 ) (diverge, diverge) diverge # diverge 4.5 Completeness of the Subtyping Relation We now have all the elements to prove the completeness of the subtyping relation. Theorem 15 (Completeness). If ### # ## # # for all calculi, then # <: # # . At several times in the proof of completeness, we need to prove an inclusion ## 1 # # ## # 1 # assuming that an inclusion between the semantics of two types built from # 1 and # # 1 (for instance, ## 1 × # 2 # # ## # 1 × # # 2 #) holds. The proof is similar in each case. Let us call typed transformation a pair of a function F from types to types and a function f from terms to terms such that, for all type # and all term e, e # ### if and only if f(e) # #F (#)#. Then, it is easy to see that, if (F, f) is a typed transformation and #F (#)# # #F (# # )#, then ### # ## # #, We thus define three families of typed transformations. Lemma 16 (Typed Transformations). The following families of pairs of functions are typed transformations (for the calculus of Sect. 3). F 1 (# # ) : # ## # × # # f 1 : e ## (e, diverge) F 2 (# # ) : # ## # # × # f 2 : e ## (diverge, e) F 3 (# # ) : # ## # # # # f 3 : e ## #x.e Proof (of Theorem 15: Completeness). We interprete the semantics of types in the calculus defined in Sect. 3. In order to handle the contravariance of the function type, we simultaneously prove by induction on # and # # that if ### # ## # # then # <: # # , and if ## # # # ### then # # <: # . For each pair of type # and # # , we prove that if ### # ## # #, then there exists a subtyping rule whose conclusion is # <: # # and whose premises are a consequence of the induction hypothesis. -- Case ### # ###. By rule Bottom, we have # <: # . -- Case ## # # # # # ## ## #. This implies ### # ## ## # and ## # # # ## ## #. Hence, by induction hypothesis, # <: # ## and # # <: # ## . Finally, by rule Union­Left, # # # # <: # ## . -- Case ### # ###. By lemma 6 (Least Semantic Type), the set ### does not contain any value. By Lemma 14 (Directed Set), ### contains at least one value. Thus, this case is not possible. -- Case ### # ## # # # #. This is a direct corollary of Lemmas 14 (Directed Set) and 8 (Prime when Directed). -- Case ### # ## # # where # and # # are distinct constructed types. By Lem­ mas 14 (Directed Set) and 13 (Homogeneity), constructed types all contain at least a value, and their values are homogeneous. Hence, ### contains a value which is not in ## # #. This case is not possible. -- Case ## 2 # # 1 # # ## 4 # # 3 #. We prove that ## 1 # # ## 3 # and ## 4 # # ## 2 #. This allow us to conclude by induction hypothesis and rule Function. The inclusion ## 1 # # ## 3 # is a direct consequence of Lemma 16 (Typed Transformations). Let us prove that ## 4 # # ## 2 #. It is su#cient to show that ## 2 # # # ## 4 # # . Let c in ## 2 # # . By Lemma 11 (Context as Function), #c# # ## 2 # # ## 1 # = ## 2 # # 1 # # ## 4 # # 3 # = ## 4 # # ## 3 #. Hence, by this lemma again, c # ## 4 # # . -- Case ## 1 × # 2 # # ## 3 × # 4 #. By Lemma 16 (Typed Transformations), ## 1 # # ## 3 # and ## 2 # # ## 4 #. We conclude by induction and rule Pair. # # The proof of the completeness theorem actually leaded us to use an orthogonality relation to define types. Indeed, for completeness to hold, we must have that, if # 1 # # <: # 2 # # , then # 2 <: # 1 . This means that, if a term e has type # 2 but not type # 1 , then there must exist a function e # of type # 1 # # but not # 2 # # . Given that the term e has type # 2 , a natural way to prove that the function e # does not have type # 2 # # is to show that the term e # e does not have type # . So, now, for any term e of type # 2 but not # 1 , we must be able to find a function of type # 1 # # such that the term e # e does not have type # . This must hold for any type # 2 , so the assumption that the term e has type # 2 does not really put any constraint on the term e and it is natural to drop it. So, finally, we would like that if a term e does not have type # 1 , then there is a function e # of type # 1 # # such that e # e does not have type # . In other words, if e ## ## 1 #, then there exists a function e # # ## 1 # fun such that e and e # are not orthogonal. That is, if a term is orthogonal to all functions in ## 1 # fun , then it should have type ## 1 #: the set ## 1 # must be closed. A noteworthy point in this discussion is that if # is not a subtype of # # , then it is unsafe to apply a function accepting terms of type # # to a term of type # . Lemma 17. For the calculus of Sect. 3, if # is not a subtype of # # , then there exists a term e in ### and a function e # in ## # # ## such that e # e # error. 5 Related Work This work is a continuation of our work with Melli‘es on semantic types [6, 7]. These two papers focus on defining types, especially recursive types, as set of terms, while we study here the subtyping relation induced by these definitions. Defining the semantics of types as closed sets of terms is very natural. For instance, in domain theory, types can be interpreted as ideals [8], that is, sets that are downward closed and closed under directed limits. Reducibility candi­ dates [9] are also closed sets of terms. Girard [10] reformulates the candidates as sets of terms closed by biorthogonality in his proof of cut elimination for linear logic. Meanwhile, Krivine [11, 12] has developped a comprehensive framework based on orthogonality, in order to analyze types as specification of terms. In semantics, Pitts [13] uses relations closed by biorthogonality to study parametric polymorphism in an operational setting. Damm [3] studies subtyping for a deterministic calculus with recursive types with union and intersection. He takes a domain theoretic approach based on the ideal model [8]. A subtyping algorithm is specified by encoding types into tree automata and defining the subtyping relation as the inclusion of the recognized languages. The soundness and completeness of this algorithm with respect to the semantics of types is proven. Frisch, Castagna and Benzaken [14] use an approach similar to ours to design a subtyping relation for a typed calculus with union and intersection types. They want to define the subtyping relation of this calculus in a semantic way, as the inclusion of the denotation of types. But their calculus is typed, so its semantics depends on the subtyping relation. In order to get rid of this circularity, they consider a family of calculi (called models). While we try to describe as large a family as possible, the authors design a family such that the subtyping relation has good properties (for instance, distributivity of union and intersection). 6 Extensions and Future Work Polymorphism and type constructors. In an extended version of the paper [4], we present a refined type system with ML­style polymorphism and type constructors and we similarly prove its soundness and completeness. This is omitted here for lack of space. Strict Pairs and Recursive Types. The type system presented here is not as rich as the type systems of XDuce [15] or CDuce [14] for two reasons. First, for the sake of simplicity, we have not considered recursive types. But we believe we have all the tools [6, 7] at hand to handle them. Second, the subtyping relation is not as rich. For instance, the two types (# 1 # # 2 ) × # and (# 1 × #) # (# 2 × #) are not equivalent according to our subtyping relation. The reason is that the family of calculi we consider is too large (as hinted in the introduction). Intersection Types. Intersection types are harder to handle than union types. The natural semantics for intersection types is set intersection: E # E # = E # E # . Then, it is clear that the dual of the subtyping rules for union types are sound. But there are other sound subtyping rules. For instance, we have (# 1 × # 3 ) # (# 2 × # 4 ) <: (# 1 # # 2 ) × (# 3 # # 4 ). Another issue is that the distributivity law (# 1 # # 2 ) # # = (# 1 # #) # (# 2 # # 2 ) does not hold in general. References 1. Pierce, B.C.: Programming with Intersection Types and Bounded Polymorphism. PhD thesis, Carnegie Mellon University (1991) Available as School of Computer Science technical report CMU­CS­91­205. 2. Dami, L.: Labelled reductions, runtime errors and operational subsumption. In Degano, P., Gorrieri, R., Marchetti­Spaccamela, A., eds.: ICALP. Volume 1256 of Lecture Notes in Computer Science., Springer (1997) 782--793 3. Damm, F.: Subtyping with union types, intersection types and recursive types II. Research Report 2259, INRIA Rennes (1994) 4. Vouillon, J.: Subtyping union types (extended version) (2004) Available from http://www.pps.jussieu.fr/~vouillon/publi/#union. 5. Coq Development Team: The Coq Proof Assistant Reference Manual -- Version V7.4. (2003) Available from http://coq.inria.fr/doc/main.html. 6. Vouillon, J., Melli‘es, P.A.: Semantic types: A fresh look at the ideal model for types. In: Proceedings of the 31th ACM Conference on Principles of Programming Languages, Venezia, Italia, ACM Press (2004) 52--63 7. Melli‘es, P.A., Vouillon, J.: Recursive polymorphic types and parametricity in an operational framework (2004) Available from http://www.pps.jussieu.fr/ ~vouillon/publi/#semtypes2. 8. MacQueen, D., Plotkin, G., Sethi, R.: An ideal model for recursive polymorphic types. Information and Control 71 (1986) 95--130 9. Girard, J.Y.: Interpr’etation fonctionelle et ’elimination des coupures dans l'ari­ thm’etique d'ordre sup’erieur. Th‘ese de doctorat d'etat, University of Paris VII (1972) 10. Girard, J.Y.: Linear logic. Theoretical Computer Science 50 (1987) 1--102 11. Danos, V., Krivine, J.L.: Disjunctive tautologies and synchronisation schemes. In: Computer Science Logic'00. Volume 1862 of Lecture Notes in Computer Science., Springer (2000) 292--301 12. Krivine, J.L.: Typed lambda­calculus in classical zermelo­fraenkel set theory. Archive of Mathematical Logic 40 (2001) 189--205 13. Pitts, A.M.: Parametric polymorphism and operational equivalence. Mathematical Structures in computer Science 10 (2000) 321--359 14. Frisch, A., Castagna, G., Benzaken, V.: Semantic subtyping. In: 17th IEEE Sympo­ sium on Logic in Computer Science, IEEE Computer Society Press (2002) 137--146 15. Hosoya, H., Vouillon, J., Pierce, B.C.: Regular expression types for XML. (ACM Transactions on Programming Languages and Systems (TOPLAS)) To appear; short version in ICFP 2000.