Giuseppe Castagna

Kim Nguyễn

Zhiwu Xu

Pietro Abate

Polymorphic Functions with Set-Theoretic Types Part 2: Local Type Inference and Type Reconstruction

Keywords: D.3.3 [Programming Languages]: Language Constructs and Features-Polymorphism Keywords Types, XML, intersection types, type constraints. 1. Introduction

This article is the second part of a two articles series about the definition of higher-order polymorphic functions in a type system with recursive types and set-theoretic type connectives (unions, intersections, and negations).

In the first part, presented in a companion paper, we defined and studied the syntax, semantics, and evaluation of the explicitlytyped version of a calculus, in which type instantiation is driven by explicit instantiation annotations. In this second part we present a local type inference system that allows the programmer to omit explicit instantiation annotations for function applications, and a type reconstruction system that allows the programmer to omit explicit type annotations for function definitions.

be an Haskell function were it not for two oddities: its type declaration contains type connectives (type intersection "∧" and type difference "\"); and the pattern in the case expression is a type, meaning that it matches all values returned by the matched expression that have that type. So what does the even function do? It checks whether its argument is an integer; if it is so it returns whether the integer is even or not, otherwise it returns its argument as it received it. Although the definition of even may seem weird, it follows a very common pattern used to manipulate functional datastructures. Two examples are Okasaki's functional implementation of red-black trees (for which our system provides a far better typing) and the transformation of XML documents whose elements are modified or left unchanged according to their tag/type (see actual code in Section 3.3 later on and in Appendix A). Furthermore it is a perfect minimal example to illustrate all the aspects of our system.

In Part 1 [START_REF] Castagna | Polymorphic functions with set-theoretic types. Part 1: Syntax, semantics, and evaluation[END_REF] we showed that the system presented there is expressive enough to define the two functions above and to verify that they have the types declared in their signatures. That map has the declared type will come as no surprise (in practice, we actually want the system to infer this type even in the absence of a signature given by the programmer: see Section 7). That even was given an intersection type means that it must have all the types that form the intersection. So it must be a function that when applied to an integer it returns a Boolean and that when applied to an argument of a type that does not contain any integer, it returns a result of the same type. In other terms, even is a polymorphic (dynamically bounded) overloaded function. However, the system in Part 1 [START_REF] Castagna | Polymorphic functions with set-theoretic types. Part 1: Syntax, semantics, and evaluation[END_REF] is not able to infer (without the help of the programmer) the type of the partial application of map to even, which must be equivalent to map even ::

([Int] -> [Bool]) ∧ ([γ\Int] -> [γ\Int]) ∧ (1

) ([γ∨Int] -> [(γ\Int)∨Bool])

since map even returns a function that when applied to a list of integers it returns a list of Booleans; when applied to a list that does not contain any integer, then it returns a list of the same type (actually, the same list); and when it is applied to a list that may contain some integers (eg, a list of reals), then it returns a list of the same type, without the integers but with some Booleans instead (in the case of reals, a list with Booleans and reals that are not integers).

Typing map even is difficult because it demands to infer several different instantiations 1 of the type of map and then take their intersection. This is why the calculus in [START_REF] Castagna | Polymorphic functions with set-theoretic types. Part 1: Syntax, semantics, and evaluation[END_REF] includes explicit type substitutions: the programmer must explicitly provide the typesubstitutions used to instantiate the types of the terms that form an application, a requirement that makes the system of [START_REF] Castagna | Polymorphic functions with set-theoretic types. Part 1: Syntax, semantics, and evaluation[END_REF] not usable in practice, yet. In this paper we remove this limitation by defining a sound and complete inference system that deduces the type-substitutions that a programmer should insert in a program of [START_REF] Castagna | Polymorphic functions with set-theoretic types. Part 1: Syntax, semantics, and evaluation[END_REF] to make it well typed. In other words, we define "local type inference" 2 for [START_REF] Castagna | Polymorphic functions with set-theoretic types. Part 1: Syntax, semantics, and evaluation[END_REF], namely, we solve the problem of checking whether there exist some type-substitutions that make the types of a function and of its arguments compatible and, if so, of inferring the type of the application as we did for [START_REF] Aiken | Type inclusion constraints and type inference[END_REF]. In particular, we show that local type inference for [START_REF] Castagna | Polymorphic functions with set-theoretic types. Part 1: Syntax, semantics, and evaluation[END_REF] reduces to the problem of finding two sets of type substitutions {σi | i∈I} and {σ ′ j | j∈J} such that for two given types s and t the relation i∈I sσi ≤ j∈J tσ ′ j holds, and we give a sound and complete algorithm for this problem. We also show how the same algorithm can be used to perform type reconstruction and infer types more precise than those inferred by the type systems of the ML family. All detailed proofs and complete definitions can be found in the Appendix. The system is fully implemented and, at the moment of writing, in alpha-test. It will be distributed in the next public release of the CDuce language [START_REF] Benzaken | CDuce: an XML-friendly general purpose language[END_REF]. In the meanwhile, the current version can be tested by compiling the master branch of the CDuce git repository: git clone https://git.cduce.org/cduce (we recommend to check the bugtracker for current issues).

Next section outlines the various problems to be faced in this research and succinctly describes the system of [START_REF] Castagna | Polymorphic functions with set-theoretic types. Part 1: Syntax, semantics, and evaluation[END_REF]. The reader acquainted with the work in [START_REF] Castagna | Polymorphic functions with set-theoretic types. Part 1: Syntax, semantics, and evaluation[END_REF] can skip directly to Section 2.1.

Overview

The aim of this research is the definition an XML processing functional language with high-order polymorphic functions, that is, in the specific, a polymorphic version of the language CDuce [START_REF] Benzaken | CDuce: an XML-friendly general purpose language[END_REF]. CDuce is a strongly-typed programming language that eases the manipulation of data in XML format. Issued from academic research it is used in production, available on different platforms, and included in all major Linux distributions. The essence of CDuce is a λ-calculus with pairs, explicitly-typed recursive functions, and a type-case expression. Its types can be recursively defined and include basic, arrow, and product type constructors and the intersection, union, and negation type connectives. In this work we omit for brevity recursive functions and product types constructors and expressions (our results can be easily extended to them as sketched in Section 5 and detailed in the appendixes) and add type variables. So in the rest of this work we study a calculus whose types and expressions are described by the next two following definitions. Definition 2.1 (Types). Types are the regular trees coinductively generated by the following productions:

t ::= b | t → t | t ∧ t | t ∨ t | ¬t | 0 | 1 | α (2)
and such that every infinite branch contains infinitely many occurrences of "→" constructor. We use T to denote the set of all types.

In the definition, b ranges over basic types (eg, Int, Bool), α ranges over type variables, and 0 and 1 respectively denote the empty (that types no value) and top (that types all values) types. Coinduction accounts for recursive types and the condition on infinite branches bars out ill-formed types such as t = t ∨ t (which does not carry any information about the set denoted by the type) or t = ¬t (which cannot represent any set). It also ensures that the binary relation ⊲ ⊆ T 2 defined by t1 ∨ t2 ⊲ ti, t1 ∧ t2 ⊲ ti, ¬t ⊲ t is Noetherian. This gives an induction principle on T that we will use without any further explicit reference to the relation. We use var(t) to denote the set of type variables occurring in a type t.

2 There are different definitions for local type inference. Here we use it with the meaning of finding the type of an expression in which not all type annotations are specified. This is the acceptation used in Scala where, like in C# and Java, type parameters for polymorphic/generic method calls can be omitted. In our specific problem, we will omit -and, thus, infer-the annotations that specify how the types of a function and of its argument can be made compatible. As explained in Section 6 it is more general than Pierce and Turner's local type inference for arguments types [START_REF] Pierce | Local type inference[END_REF].

A type t is said to be ground or closed if and only if var(t) is empty. The subtyping relation for these types is the one defined by Castagna and Xu [START_REF] Castagna | Set-theoretic Foundation of Parametric Polymorphism and Subtyping[END_REF]. For this work it suffices to consider that ground types are interpreted as sets of values (ie, either constants or λ-abstractions) that have that type, and that subtyping is set containment (a ground type s is a subtype of a ground type t if and only if t contains all the values of type s). In particular, s→t contains all λ-abstractions that when applied to a value of type s, if the computation terminates, then they return a result of type t (eg, 0→1 is the set of all functions 3 and 1→0 is the set of functions that diverge on every argument). Type connectives (ie, union, intersection, negation) are interpreted as the corresponding set-theoretic operators (eg, s ∨ t is the union of the values of the two types). For what concerns non-ground types (ie, types with variables occurring in them) all the reader needs to know for this work is that the subtyping relation of Castagna and Xu is preserved by substitution of the type variables. Namely, if s ≤ t, then sσ ≤ tσ for every type-substitution σ (the converse does not hold in general, while it holds for semantic type-substitutions in convex models: see [START_REF] Castagna | Set-theoretic Foundation of Parametric Polymorphism and Subtyping[END_REF]). Two types are equivalent if they are subtype one of each other (type equivalence is denoted by ≃).

Finally, notice that in this system s ≤ t if and only if s∧¬t ≤ 0.

and such that in every expression e∈t ? e1 : e2 the type t is closed.

In the definition, c ranges over constants (eg, true, false, 1, 2, ...) which are values of basic types (we use bc to denote the basic type of the constant c); x ranges over expression variables; e∈t ? e1 : e2 denotes the type-case expression that evaluates either e1 or e2 according to whether the value returned by e (if any) is of type t or not; λ ∧ i∈I s i →t i x.e is a value of type ∧i∈I si → ti and denotes the function of parameter x and body e. An expression has an intersection type if and only if it has all the types that compose the intersection. Therefore, intuitively, λ ∧ i∈I s i →t i x.e is a well-typed value if for all i∈I the hypothesis that x is of type si implies that the body e has type ti, that is to say, it is well typed if λ ∧ i∈I s i →t i x.e has type si → ti for all i ∈ I.

As we said at the beginning of the section, the functional core of CDuce [START_REF] Benzaken | CDuce: an XML-friendly general purpose language[END_REF] has exactly the same types and expressions as the above except for two single differences: (i) its types do not contain type variables and (ii) it includes product types and recursive functions, which we omitted here for brevity. The reasons why in CDuce (and in its polymorphic extension we study here) there is a type-case expressions and why λ-expressions are explicitly annotated by their intersection types are explained in details in the companion paper that presents the first part of this work [START_REF] Castagna | Polymorphic functions with set-theoretic types. Part 1: Syntax, semantics, and evaluation[END_REF] and to which the reader can refer. The novelty of this research with respect to CDuce, thus, is to allow type variables to occur in the types that annotate λabstractions. It becomes thus possible to define the polymorphic identity function as λ α→α x.x, while the classic "auto-application" term is written as λ ((α→β)∧α)→β x.xx. The intended meaning of using a type variable, such as α, is that a (well-typed) λ-abstraction not only has the type specified in its label (and by subsumption all its super-types) but also all types obtained by instantiating the type variables occurring in its label. So λ α→α x.x has not only type α → α but by subsumption also, for instance, the types 0→1 (the type of all functions, which is a super-type of α→α) and ¬Int (the type of all non integer values), and by instantiation the types Int→Int, Bool→Bool, etc. The addition of type variables and instantiation makes the calculus a full-fledged intersection type system (see Section 3.5 in [START_REF] Castagna | Polymorphic functions with set-theoretic types. Part 1: Syntax, semantics, and evaluation[END_REF]): for instance, by combining intersections, instantiation, and subtyping, it is possible to deduce that λ α→α x.x has type (Int→Int) ∧ (Bool→Bool) ∧ ¬Int.

The key problem to be solved, then, is to define an explicitlytyped λ-calculus with intersection types and a type-case expression. This is technically quite challenging because of three main reasons: (i) type instantiation must be explicit, (ii) it may require the use of sets of type-substitutions, and (iii) it cannot always be immediately propagated to the body of a function. A detailed description of these reasons can be found in [START_REF] Castagna | Polymorphic functions with set-theoretic types. Part 1: Syntax, semantics, and evaluation[END_REF] but, in a nutshell:

(i) instantiation must be explicit because of the presence of a type-case: we check the type of a function by checking its type annotation, thus any type-substitution of variables of an annotation must be explicitly propagated. That is, to apply λ α→α x.x to 42 we must first apply the type-substitution { Int / α } to it, yielding λ Int→Int x.x, and only then we can apply the function to 42.

(ii) sets of type-substitutions are needed because of intersection types. A function that expects arguments of type (Int→Int) ∧ (Bool→Bool) can be safely applied to λ α→α x.x, but the latter must be previously instantiated by a set of two type-substitutions [{ Int / α }, { Bool / α }], yielding λ (Int→Int)∧ (Bool→Bool) x.x (the application of a set of substitution to a type t returns the intersection of all types obtained by applying each substitutions in the set to t).

(iii) type-substitutions cannot be immediately applied to the body of a function since this may yield ill-typed terms. For instance, consider the following "daffy" definition of the identity function

(λ α→α x.(λ α→α y.x)x) (4)
and apply it to the same set of substitutions as before, namely, [{ Int / α }, { Bool / α }]. This yields the following term (λ (Int→Int)∧ (Bool→Bool) x.(λ (Int→Int)∧(Bool→Bool) y.x)x) (5) which is not well typed: to type it one should prove that under the hypothesis x : Int the term (λ (Int→Int)∧(Bool→Bool) y.x)x has type Int, and that under the hypothesis x : Bool this same term has type Bool, but both checks fail because, in both cases, λ (Int→Int)∧(Bool→Bool) y.x is ill-typed (it neither has type Int→Int when x : Bool, nor has it type Bool→Bool when x : Int).

To cope with these three problems we proposed in Part 1 [START_REF] Castagna | Polymorphic functions with set-theoretic types. Part 1: Syntax, semantics, and evaluation[END_REF] that the instantiation of the body of a function changes according to the type of the argument of the function. For instance, when we apply the daffy identity function to an integer we must instantiate its body by the type-substitution { Int / α }, while the type-substitution { Bool / α } must be used when the function argument is a Boolean value. To obtain this behavior, in Part 1 [START_REF] Castagna | Polymorphic functions with set-theoretic types. Part 1: Syntax, semantics, and evaluation[END_REF] we introduced and studied a "lazy" instantiation of function bodies, which delays the propagation of a set of substitutions to the function body until the precise type of the function argument is known. This is obtained by decorating λ-abstractions by (sets of) type-substitutions. For example, in order to pass our daffy identity function (4) to a function that expects arguments of type (Int→Int) ∧ (Bool→Bool) we first "lazily" instantiate it as follows:

(λ α→α [{ Int / α },{ Bool / α }] x.(λ α→α y.x)x). (6)
The annotation that subscripts the outer "λ" indicates that the function must be relabeled and, therefore, that we are using the particular instance whose type is the one in the "interface" (ie, α→α) to which we apply the set of type-substitutions in the annotation. The relabeling will be actually propagated to the body of the function at the moment of the reduction, only if and when the function is applied (relabeling is thus lazy). However, the new annotation is statically used by the type system to check type soundness. Formally, this is obtained in Part 1 [START_REF] Castagna | Polymorphic functions with set-theoretic types. Part 1: Syntax, semantics, and evaluation[END_REF] by adding explicit sets of type-substitutions (ranged over by [σj]j∈J ) to the grammar (3) of Definition 2.2. Sets of type-substitutions can be applied directly to expressions (to produce a particular expansion/instantiation of the type variables occurring in them) or, as in [START_REF] Coppo | Principal types and unification for simple intersection type systems[END_REF], they can be used to annotate λ's (to implement the lazy relabeling of the function body). This yields a calculus whose syntax is

e ::= c | x | ee | λ ∧ i∈I s i →t i [σ j ] j∈J
x.e | e∈t ? e : e | e[σj]j∈J [START_REF] Courcelle | Fundamental properties of infinite trees[END_REF] where types are those in Definition 2.1 and with the restriction that the type tested in type-case expressions is closed. We call this calculus and its expressions the explicitly-typed calculus and expressions, respectively, in order to differentiate it from the one of Definition 2.2 which does not have explicit type-substitutions and, therefore, is called the implicitly-typed calculus.

Henceforth, given a λ-abstraction λ

∧ i∈I s i →t i [σ j ] j∈J
x.e we call the type i∈I si→ti the interface of the function and the set of typesubstitutions [σj]j∈J the decoration of the function. We write λ ∧ i∈I t i →s i x.e for short when the decoration is a singleton containing just the empty substitution. We use v to range over values, that is, either constants or λ-abstractions. Let e be an expression: we use fv(e) and bv(e) respectively to denote the sets of free expression variables and bound expression variables of the expression e; we use tv(e) to denote the set of type variables occurring in e.

As customary, we assume bound expression variables to be pairwise distinct and distinct from any free expression variable occurring in the expressions under consideration. Polymorphic variables can be bound by interfaces, but also by decorations: for example, in λ β→β [{ α / β }] x.(λ α→α y.y)x, the α occurring in the interface of the inner abstraction is "bound" by the decoration [{ α / β }], and the whole expression is α-equivalent to (λ β→β [{ γ / β }] x.(λ γ→γ y.y)x). If a type variable is bound by an outer abstraction, it cannot be instantiated; such a type variable is called monomorphic. We assume that polymorphic type variables are pairwise distinct and distinct from any monomorphic type variable in the expressions under consideration. In particular, when substituting a value v for a variable x in an expression e, we suppose the polymorphic type variables of e to be distinct from the monomorphic and polymorphic type variables of v thus avoiding unwanted capture.

Both static and dynamic semantics for the explicitly-typed expressions in [START_REF] Courcelle | Fundamental properties of infinite trees[END_REF] are defined in [START_REF] Castagna | Polymorphic functions with set-theoretic types. Part 1: Syntax, semantics, and evaluation[END_REF] in terms of a relabeling operation "@" which takes an expression e and a set of type-substitutions [σj]j∈J and pushes [σj]j∈J down to all outermost λ-abstractions occurring in e (and collects and composes with the sets of typesubstitutions it meets). Precisely, e@[σj]j∈J is defined for λabstractions and applications of type-substitutions as (λ

∧ i∈I t i →s i [σ k ] k∈K x.e)@[σj]j∈J def = λ ∧ i∈I t i →s i [σ j ] j∈J •[σ k ] k∈K x.e (e[
σi]i∈I )@[σj]j∈J def = e@([σj]j∈J • [σi]i∈I ) (where • denotes the pairwise composition of all substitutions of the two sets). It erases the set of type-substitutions when e is either a variable or a constant, and it is homomorphically applied on the remaining expressions (see [START_REF] Castagna | Polymorphic functions with set-theoretic types. Part 1: Syntax, semantics, and evaluation[END_REF] for comprehensive definitions). The dynamic semantics is given by the following notions of reduction (where v denotes a value), applied by a leftmost-outermost strategy:

e[σj]j∈J e@[σj]j∈J (8)
(λ

∧ i∈I t i →s i [σ j ] j∈J x.e)v (e@[σj]j∈P ){ v / x } (9)
v∈t ? e1 : e2 e1 if ⊢ v : t e2 otherwise [START_REF] Robie | XQuery 3.0: An XML query language[END_REF] where in [START_REF] Davies | Practical Refiniment-Type Checking[END_REF] we have P def = {j∈J | ∃i∈I, ⊢ v : tiσj}. The first rule [START_REF] Damas | Principal type-schemes for functional programs[END_REF] performs relabeling, that is, it propagates the sets of type-substitutions down into the decorations of the outermost λ-abstractions. The second rule [START_REF] Davies | Practical Refiniment-Type Checking[END_REF] states the semantics of applications: this is standard call-by-value β-reduction, with the difference that the substitution of the argument for the parameter is performed on the relabeled body of the function. Notice that rela-Figure 1. Typing algorithm beling depends on the type of the argument and keeps only those type-substitutions that make the type of the argument v match (at least one of) the input types defined in the interface of the function (ie, the set P which contains all substitutions σj such that the argument v has type tiσj for some i in I: the type system statically ensures that P will never be empty). For instance, take the daffy identity function [START_REF] Castagna | Set-theoretic Foundation of Parametric Polymorphism and Subtyping[END_REF], instantiate it as in ( 6) by both Int and Bool, and apply it to 42 -ie, (λ α→α

[{ Int / α },{ Bool / α }]
x.(λ α→α y.x)x)42-, then it reduces to (λ α→α [{ Int / α }] y.42)42, (which is observationally equivalent to (λ Int→Int y.42)42) since the reduction discards the { Bool / α } substitution. Finally, the third rule [START_REF] Robie | XQuery 3.0: An XML query language[END_REF] checks whether the value returned by the expression in the type-case matches the specified type and selects the branch accordingly.

The static semantics is given by the rules in Figure 1 which form an algorithmic system (as stressed by the A subscript in ⊢ A and by the names of the rules): in every case at most one rule applies, either because of the syntax of the term or because of mutually exclusive side conditions. We invite the reader to consult [START_REF] Castagna | Polymorphic functions with set-theoretic types. Part 1: Syntax, semantics, and evaluation[END_REF] for more details (there the reader will also find a non-algorithmicand far more readable-system defined in terms of subsumption). Here we just comment the rules interesting for this second part, that is, (ALG-ABSTR), (ALG-INST), and (ALG-APP). First of all notice the presence of ∆ in judgments. This is the set of monomorphic type variables, that is, the variables that occur in the type of some outer λ-abstraction and, as such, cannot be instantiated; this set must contain all the type variables occurring in Γ. Rule (ALG-ABSTR) checks that λ

∧ i∈I t i →s i [σ j ] j∈J
x.e has the type declared by (the combination of) its interface and its decoration, that is, ∧i∈I,j∈J tiσj→siσj. To do that it first adds all the variables occurring in this type to the set ∆, (in the function body these variables are monomorphic). Then, it checks that for every possible input type -ie, for every possible combination of ti and σj-the function body e relabeled with the single type-substitution σj under consideration (ie, e@[σj]), has (a subtype of) the corresponding output type.

Rule (ALG-INST) infers for e[σj]j∈J the type obtained by applying the set of type-substitutions to the type of e, provided that the type-substitutions do not instantiate monomorphic variables (ie, for all j∈J, dom(σj) ∩ ∆ = ∅, noted as σj♯ ∆).

Rule (ALG-APPL) for applications checks that the type t of the function is a functional type (ie, t ≤ 0→1). Then it checks that the type of the argument is a subtype of the domain of t (denoted by dom(t)). Finally, it infers for the application the type t • s def = min{u | t ≤ s→u}, that is, the smallest result type that can be obtained by subsuming t to an arrow type with domain s. 4 Even if t ≤ 0→1, in general, t does not have the form of an arrow type (it could also be a union or an intersection or a negation of types) and the definition of dom(t) is not immediate. Formally, if t ≤ 0→1, then t ≃ i∈I ( p∈P i (sp→tp) ∧ n∈N i ¬(sn→tn) ∧ 4 For every type t such that t ≤ 0→1 and type s such that s ≤ dom(t), the type t • s exists and can be effectively computed. q∈Q i αq ∧ r∈R i ¬βr) where all Pi's are not empty (see Castagna and Xu [START_REF] Castagna | Set-theoretic Foundation of Parametric Polymorphism and Subtyping[END_REF]), and, for such a type t, the domain is defined as dom(t) def = i∈I p∈P i sp (see Part 1 [START_REF] Castagna | Polymorphic functions with set-theoretic types. Part 1: Syntax, semantics, and evaluation[END_REF]). The type system is sound (it satisfies both subject reduction and progress), it subsumes existing intersection type systems, and type inference is decidable. Furthermore the calculus can be compiled into an intermediate language which executes relabeling only by need and, thus, can be efficiently evaluated (again, see Part 1 [START_REF] Castagna | Polymorphic functions with set-theoretic types. Part 1: Syntax, semantics, and evaluation[END_REF]).

Before proceeding we stress again that in this calculus type-substitutions and, thus, instantiation are explicit: (λ α→α x.x)[{ Int / α }] has type Int→Int, but (λ α→α x.x) does not (contrary to ML, the semantic subtyping relation ≤ does not account for instantiation).

Overview and contributions of this article (Part 2)

Recall that we want the programmer to use the implicitly-typed expressions of grammar (3), and not those of grammar [START_REF] Courcelle | Fundamental properties of infinite trees[END_REF] which would require the programmer to write explicit type-substitutions. Therefore in Section 3 we define a local type inference system that, given an implicitly-typed expression produced by the grammar (3), checks whether and where some sets of type-substitutions can be inserted in this expression so as to make it a well-typed explicitlytyped expression of grammar [START_REF] Courcelle | Fundamental properties of infinite trees[END_REF]. Thus, our local type inference consists of a type-substitution reconstruction system, insofar as it has to reconstruct the sets of type-substitutions that make an expression of grammar (3) a well-typed expression of grammar [START_REF] Courcelle | Fundamental properties of infinite trees[END_REF]. In order to avoid ambiguity we reserve the word "reconstruction" for the problem of reconstructing type annotations (in particular, function interfaces) and speak of inference of type-substitutions for the problem of local type inference. In particular, we show that this problem can be reduced to the problem of deciding whether for two types s and t there exist two sets of type-substitutions [σi]i∈I and

[σ ′ j ]j∈J such that s[σi]i∈I ≤ t[σ ′ j ]j∈J .
We prove that when the cardinalities of I and J are given, the problem above is decidable and reduces to the problem of finding all substitutions σ such that s ′ σ ≤ t ′ σ for two given types s ′ and t ′ (we dub this latter problem the tallying problem). We show how to produce a sound and complete set of solutions for the latter problem. This is done by generating sets of constraint-sets that are then normalized, merged, and solved. The solution of the tallying problem immediately yields a semi-decision procedure (that tries all the cardinalities for I, J) for the local type inference system. Henceforth, to enhance readability, we will systematically use the metavariable "a" to denote expressions of the implicitly-typed calculus (ie, those of grammar (3)) and reserve the metavariable "e" for expressions of the explicitly-typed calculus (ie, those of grammar [START_REF] Courcelle | Fundamental properties of infinite trees[END_REF]). Finally, in Section 4 we show that the theory and algorithms developed in Section 3 can be reused to do ML-like type reconstruction, that is, to infer the interface of unannotated λ-expressions in a pure λ-calculus with type-case.

In summary, the results of this paper make it possible to program in the implicitly-typed calculus [START_REF] Castagna | Polymorphic functions with set-theoretic types. Part 1: Syntax, semantics, and evaluation[END_REF], by compiling it into welltyped explicitly-typed expressions [START_REF] Courcelle | Fundamental properties of infinite trees[END_REF] defined in [START_REF] Castagna | Polymorphic functions with set-theoretic types. Part 1: Syntax, semantics, and evaluation[END_REF]. Let us show the details on the motivating example of the introduction. First, note that in the implicitly-typed calculus (3) even can be defined as λ (Int→Bool)∧(α\Int→α\Int) x . x∈Int ? (x mod 2) = 0 : x (11) (where s\t is syntactic sugar for s∧¬t) while -with the products and recursive function definitions given in the appendixmap is

µm (α→β)→[α]→[β] f = λ [α]→[β] ℓ . ℓ∈nil ? nil : (f (π1ℓ),mf (π2ℓ)) (12)
where the type nil tested in the type case denotes the singleton type that contains just the constant nil, and [α] denotes the regular type that is the least solution of X = (α, X) ∨ nil.

If we feed these two expressions to the type-checker (the rules in Figure 1 suffice since no local type inference is needed to type these two functions) it confirms that both are well typed and have the types declared in their interfaces. To apply (the expression [START_REF] Frisch | Semantic subtyping: dealing set-theoretically with function, union, intersection, and negation types[END_REF] defining) map to (the expression [START_REF] Frisch | Théorie, conception et réalisation d'un langage de programmation fonctionnel adapté à XML[END_REF] defining) even we need to instantiate map, that is, to perform local type inference. The inference system of Section 3 infers the following set of typesubstitutions [{ (γ\Int) / α , (γ\Int) / β }, { γ∨Int / α , (γ\Int)∨Bool / β }] and textually inserts it between the two terms (so that the typesubstitutions apply to the type variables of map) yielding a typing equivalent to the one in [START_REF] Aiken | Type inclusion constraints and type inference[END_REF]. The expression with the inserted set of type-substitutions is compiled into the intermediate language defined in Section 5 of Part 1 [START_REF] Castagna | Polymorphic functions with set-theoretic types. Part 1: Syntax, semantics, and evaluation[END_REF] and executed as efficiently as if it were a monomorphic expression. Finally, in Section 4 we show that we could allow the programmer to omit the type declaration for map -ie, map :: (α -> β) -> [α] -> [β]-, since it is possible to reuse the algorithms developed in Section 3 to reconstruct for map a type slightly more precise than the one above.

Contributions:

The overall contribution of this work (Parts 1 and 2) is the definition of a statically-typed calculus with polymorphic higher-order functions in a type system with recursive types and union, intersection, and negation type connectives, and local type inference. The technical contributions of this Part 2 are: -the definition of an algorithm that for any pair of polymorphic regular tree types t1 and t2 produces a sound and complete set of solutions to the problem of deciding whether there exists a typesubstitution σ such that t1σ ≤ t2σ. This is obtained by using the set-theoretic interpretation of types to reduce the problem to a unification problem on regular tree types. -the definition of a type-substitution inference system sound and complete w.r.t. the system of the explicitly-typed calculus of [START_REF] Castagna | Polymorphic functions with set-theoretic types. Part 1: Syntax, semantics, and evaluation[END_REF]. -the definition of a sound and complete algorithm for local type inference for the calculus. The algorithm yields a semi-decision procedure for the typeability of a λ-calculus with intersection and recursive types and with explicitly-typed λ-abstractions. -the definition of a type reconstruction algorithm that uses the machinery developed for local type inference and improves reconstruction defined for ML languages. We also provide two different implementations: a prototype implementation of the calculus presented here and the polymorphic extension of the compiler of CDuce, a production-grade language.

Inference of type-substitutions

Since we want the programmer to program in the implicitly-typed calculus (3), then it is the task of the type-substitution inference system to check whether it is possible to insert some type-substitutions in appropriate places of the expression written by the programmer so that the resulting expression is a well-typed explicitly-typed expression of the grammar in [START_REF] Courcelle | Fundamental properties of infinite trees[END_REF]. To define the type-substitution inference system we proceed in two steps. First, we define a syntaxdirected deduction system for the implicitly-typed calculus by modifying the one in Figure 1: whenever the old system checks a subtyping relation, the new system tries to guess some explicit typesubstitutions to insert in that position. Second, we show how to compute the operations used by the deduction system defined in the first step. Each of these steps is developed in one of the following subsections.

Type substitution assignment

In this section we define an inference system for the implicitlytyped calculus of Definition 2.2. The system will be sound and complete with respect to explicitly-typed one modulo a single exception: we will not try to insert type-substitutions in decorations, that is, we will consider only expressions in the explicitly-typed calculus in which all decorations are absent (ie, they are a singleton set that contains only the empty type-substitution). There is no technical problem to infer also type-substitutions in decorations. Not doing so is just a design choice suggested by common sense so as to match the programmer's intuition: if we write an expression such as λ α→α x.3 we want to infer that it is ill-typed (as, say, Haskell does); but if we allowed to infer decorations, then the expression could be typed by inserting a decoration as in λ α→α [{ Int / α }] x.3. Likewise, if the programmer specified the signature map::(α->β)->γ, we expect the system to answer that the definition of map does not conform this signature, rather than it conforms the signature by substituting [α]->[β] for γ (alternatively, we must omit the signature altogether and let the system infer it: see Section 4 on reconstruction).

We have to define a system that guesses where sets of typesubstitutions must be inserted so that an implicitly-typed expression is transformed into an explicitly-typed expression that is well typed in the system of Figure 1. The general role of type-substitutions is to make the type of some expression satisfy some subtyping constraints. Examples of this are the type of the body of a function which must match the result type declared in the interface, or the type of the argument of a function which must be a subtype of the domain of the function. Actually all the cases in which subtyping constraints must be satisfied are enumerated in Figure 1: they coincide with the subtyping relation checks that occur in the rules. Figure 1 is our Ariadne's thread through the definition of the type-substitution inference system: the rule (ALG-INST) must be removed and wherever the typing algorithm in Figure 1 checks whether for some types s and t the relation s ≤ t holds, then the type-substitution inference system must check whether there exists a set of type-substitutions [σi]i∈I for the polymorphic variables (ie, those not in ∆) that makes s[σi]i∈I ≤ t hold. The reader may wonder why we apply the type-substitution only on the smaller type and not on both types. The reason can be understood by looking at the rules in Figure 1 and seeing that whenever a subtyping relation is specified, the right-hand side type cannot be instantiated: either because it is a ground type (rules (ALG-CASE-*)) or because it is a type in an interface and inferring a type-substitution for it would correspond to inferring a type-substitution in a decoration (rule (ALG-ABSTR)). The only exception to this is the rule (ALG-APPL) for application, but for it we will introduce a specific operator later in this section.

In order to ease the presentation it is handy to introduce a family of preorders ⊑∆ that combine subtyping and instantiation: Definition 3.1. Let s and t be two types, ∆ a set of type variables, and [σi]i∈I a set of type-substitutions. We define:

[σi]i∈I s ⊑∆ t def ⇐⇒ i∈I sσi ≤ t and ∀i∈I. σi ♯ ∆ s ⊑∆ t def ⇐⇒ ∃[σi]i∈I such that [σi]i∈I s ⊑∆ t
Intuitively, it suffices to replace ≤ by ⊑∆ and ≤ by ⊑∆ in the algorithmic rules of Figure 1 (where ∆ is the set of monomorphic variables used in the premises) to obtain the corresponding rules of type-substitution inference. This yields the system formed by the rules in Figure 2 (we subscripted the turnstile symbol by I to stress that it is the Inference system for type-substitutions) plus

(INF-ABSTR) ∆ ∪ ∆ ′ ; Γ, x : ti ⊢ I a : s ′ i ∆ ; Γ ⊢ I λ ∧ i∈I t i →s i x.a : i∈I (ti → si) ∆ ′ = var(∧ i∈I t i →s i ) s ′ i ⊑ ∆∪∆ ′ s i , i∈I (INF-CASE-BOTH) ∆ ; Γ ⊢ I a : t ′ ∆ ; Γ ⊢ I a1 : s1 ∆ ; Γ ⊢ I a2 : s2 ∆ ; Γ ⊢ I (a∈t ? a1 : a2) : s1 ∨ s2 t ′ ⊑ ∆ ¬t t ′ ⊑ ∆ t (INF-CASE-FST) ∆ ; Γ ⊢ I a : t ′ ∆ ; Γ ⊢ I a1 : s1 ∆ ; Γ ⊢ I (a∈t ? a1 : a2) : s1 t ′ ⊑ ∆ t (INF-CASE-SND) ∆ ; Γ ⊢ I a : t ′ ∆ ; Γ ⊢ I a2 : s2 ∆ ; Γ ⊢ I (a∈t ? a1 : a2) : s2 t ′ ⊑ ∆ ¬t (INF-APPL) ∆ ; Γ ⊢ I a1 : t ∆ ; Γ ⊢ I a2 : s ∆ ; Γ ⊢ I a1a2 : u u∈(t •∆ s) Figure 2.
Inference system for type-substitutions the rules for constants and variables (omitted: they are the same as in Figure 1). Of particular interest is the rule (INF-ABSTR) which has become simpler than in Figure 1 since it works under the hypothesis that λ-abstractions have empty decorations, and which uses the ∆∪∆ ′ set to compare the types of the body with the result types specified in the interface (s ′ i ⊑ ∆∪∆ ′ si). Notice that we do not require the sets of type-substitutions that make s ′ i ⊑ ∆∪∆ ′ si satisfied to be the same for all i∈I: this is not a problem since the case of different sets of type-substitutions corresponds to using their union as sets of type-substitutions (ie, to intersecting them point-wise: see Definition B.9 and Corollary B.12 -henceforth, references starting with letters refer to appendixes).

It still remains the most delicate rule, (INF-APPL), the one for application. It is difficult because not only it must find two distinct sets of type-substitutions (one for the function type the other for the argument type) but also because the set of type-substitutions for the function type must enforce two distinct constraints: the type resulting from applying the set of type-susbstitutions to the type of the function must be a subtype of 0→1, and its domain must be compatible with (ie, a supertype of) the type inferred for the argument. In order to solve all these constraints we collapse them into a single definition which is the algorithmic counterpart of the set of types used in Section 2 to define the operation t • s occurring in the rule (ALG-APPL). Precisely, we define t•∆s as the set of types for which there exist two sets of type-substitutions (for variables not in ∆) that make s compatible with the domain of t:

t •∆ s def =    u [σj]j∈J t ⊑∆ 0→1 [σi]i∈I s ⊑∆ dom(t[σj]j∈J ) u = t[σj]j∈J • s[σi]i∈I   
In practice, this set takes all the pairs of sets of type-substitutions that make t a function type, and s an argument type compatible with t and collects all the possible result types. This set is closed by intersection (see Lemma B.8) which is an important property since it ensures that if we find two distinct solutions to type an application, then we can also use their intersection. Unfortunately, this property is not enough to ensure that this set has a minimum type (for that we also need to prove that the intersection of all the types in the set can be expressed as a finite intersection) which would imply the existence of a principal type (which is still an open problem). For the application of a function of type t to an argument of type s, the inference system deduces every type in t •∆ s. This yields the inference rule (INF-APPL) of Figure 2.

These type-substitution inference rules are sound and complete with respect to the typing algorithm, modulo the restriction that all the decorations in the λ-abstractions are empty. Both of these properties are stated in terms of the erase(.) function that maps expressions of the explicitly-typed calculus into expressions of the implicitly-typed one by erasing in the former all occurrences of sets of type-substitutions. Theorem 3.2 (Soundness of inference). Let a be an implicitlytyped expression. If ∆ ; Γ ⊢ I a : t, then there exists an explicitlytyped expression e such that erase(e) = a and ∆ ; Γ ⊢ A e : t.

The proof of the soundness property is constructive: it builds along the derivation for the implicitly-typed expressions a an explicitlytyped expression e that satisfies the statement of the theorem; this expression is the one that is then compiled in the intermediate language we defined in Part 1 [START_REF] Castagna | Polymorphic functions with set-theoretic types. Part 1: Syntax, semantics, and evaluation[END_REF] and evaluated. Notice that ⊑∆ gauges the generality of the solutions found by the inference system: the smaller the type found, the more general the solution is. As a matter of fact, adding to the system in Figure 2 a subsumption rule that uses the relation ⊑∆ that is:

(SUBSUMPTION) ∆ ; Γ ⊢ I a : t1 t1⊑∆t2
∆ ; Γ ⊢ I a : t2 is sound. This means that the set of solutions is upward closed with respect to ⊑∆ and that from smaller solutions it is possible (by such a subsumption rule) to deduce the larger ones. In that respect, the completeness theorem that follows states that the inference system can always deduce for the erasure of an expression a solution that is at least as good as the one deduced for that expression by the type system for the explicitly-typed calculus.

Theorem 3.3 (Completeness of inference)

. Let e be an (explicitlytyped) expression in which all decorations are empty. If ∆ ; Γ ⊢ A e : t, then there exists a type t ′ such that ∆ ; Γ ⊢ I erase(e) : t ′ and t ′ ⊑∆ t.

The inference system is syntax directed and describes an algorithm that is parametric in the decision procedures for ⊑∆ and •∆ . The problem of deciding these two relations is tackled next.

Type tallying

We define the tallying problem as follows Definition 3.4 (Tallying problem). Let C be a constraint-set, that is, a finite set of pairs of types (these pairs are called constraints), and ∆ a finite set of type variables. A type-substitution σ is a solution for the tallying problem of C and ∆ (noted σ ∆ C) if σ♯∆ and for all (s, t) ∈ C, sσ ≤ tσ holds. Thus a constraint-set corresponds to the logical conjunction of the constraints that compose it, and the tallying problem searches for a type-substitution that satisfies this conjunction. The definition of the tallying problem is the cornerstone of our type-substitution inference system, since every problem we have to solve to "implement" the rules of Figure 2 is reduced to different instances of this problem.

With the exception of (INF-APPL), it is not difficult to show that the "implementation" of the rules of the type-substitution inference system ⊢ I corresponds to finding and solving a particular tallying problem. First, notice that for the remaining rules the problem we have to solve is to prove (or disprove) the relation s ⊑∆ t for given s and t. By definition this corresponds to finding a set of n type-substitutions [σi] i≤n such that i≤n sσi ≤ t. We can split each type-substitution σi in two: a renaming type-substitution ρi that maps each variable of s not in ∆ into a fresh type variable, and a type substitution The (INF-APPL) rule deserves a special treatment since it needs to solve a more difficult problem. A "solution" for the (INF-APPL) rule problem is a pair of sets of type-substitutions [σi]i∈I , [σj]j∈J for variables not in ∆ such that both i∈I tσi ≤ 0→1 and j∈J sσj ≤ dom( i∈I tσi) hold. In this section we give an algorithm that produces a set of solutions for the (INF-APPL) rule problem that is sound (it finds only correct solutions) and complete (any other solution can be derived from those returned by the algorithm). To this end we proceed in three steps: (i) given a tallying problem, we show how to effectively produce a finite set of solutions that is sound (it contains only correct solutions) and complete (every other solution of the problem is less general-in the usual sense of unification, ie, it is larger wrt ⊑-than some solution in the set); (ii) we show that if we fix the cardinalities of I and J, then it is possible to reduce the (INF-APPL) rule problem to a tallying problem; (iii) from this we deduce a sound and complete algorithm to semi-decide the general (INF-APPL) rule problem and thus the whole inference system.

σ ′ i such that σi = σ ′ i • ρi.
We solve each problem in one of the next subsections, but before we recall an important property of semantic subtyping systems [START_REF] Castagna | Set-theoretic Foundation of Parametric Polymorphism and Subtyping[END_REF][START_REF] Frisch | Semantic subtyping: dealing set-theoretically with function, union, intersection, and negation types[END_REF] which states that every type is equivalent to (and can be effectively transformed into) a type in disjunctive normal form, that is, a union of uniform intersections of literals. A literal is either an arrow, or a basic type, or a type variable, or a negation thereof. An intersection is uniform if it is composed of literals with the same constructor, that is, either it is an intersection of arrows, type variables, and their negations or it is an intersection of basic types, type variables, and their negations. In summary, a disjunctive normal form is a union of summands whose form is either

p∈P bp ∧ n∈N ¬bn ∧ q∈P ′ αq ∧ r∈N ′ ¬αr (13) or p∈P (sp→tp) ∧ n∈N ¬(sn→tn) ∧ q∈P ′ αq ∧ r∈N ′ ¬αr (14)
When either P ′ or N ′ is non empty, we call the variables αq's and αr's the top-level variables of the normal form.

Solution of the tallying problem.

In order to solve the tallying problem for given ∆ and C, we first fix some total order -any will do-on the type variables occurring in C and not in ∆ (from now on, when speaking of type variables we will mean type variables not in ∆), order that will be used to ensure that all inferred types satisfy the contractivity condition of Definition 2.1. Next, we produce sets of constraint-sets (as a single constraint-set corresponds to logical conjunction, so a set of constraint-sets corresponds to disjunction of the corresponding conjunctions) in a particular form by proceeding in four steps: first, we normalize the constraint-sets (so that at least one of the two types of every constraint is a type variable); second, we merge constraints that are on the same variables; third, we solve all these constraint-sets by producing solvable sets of equations equivalent to the original problem and then solving these equations; fourth, we combine these three steps into an algorithm that produces a sound and complete set of solutions of the tallying problem. To this end we define two operations on sets of constraint-sets: Definition 3.5. Let S1, S2 ⊆ P(T × T ) be two sets of constraint-sets. We define

S1 ⊓ S2 def = {C1 ∪ C2 | C1 ∈ S1, C2 ∈ S2} S1 ⊔ S2 def = S1 ∪ S2
By convention the empty set of constraint-sets is unsolvable (it denotes failure in finding a solution), while the set containing the empty set is always satisfied.

We also define an auxiliary function single that singles out a given top-level variable of a normal form. More precisely, given a type t which is a summand of a normal form, that is, t = p∈P tp ∧ n∈N ¬tn ∧ q∈P ′ αq ∧ r∈N ′ ¬αr and k ∈ P ′ ∪N ′ , we define single(α k , t) as the constraint equivalent to t ≤ 0 in which α k is "singled-out", that is, 5p∈P tp ∧ n∈N ¬tn ∧ q∈P ′ αq ∧ r∈(N ′ \{k}) ¬αr ≤ α k when k ∈ N ′ and α k ≤ p∈P ¬tp ∨ n∈N tn ∨ q∈(P ′ \{k}) ¬αq ∧ r∈N ′ αr when k ∈ P ′ . Henceforth, to enhance readability we will often write s ≤ t for the constraint (s, t), as we did above. EXAMPLE. We will show the various phases of the process by solving the tallying problem for the following constraint-set:

C = {(α → Bool, β → β) , (Int∨Bool → Int , α → β)
} and assume that α β.

Constraint normalization.

We define a function norm that takes a type t and generates a set of normalized constraint-sets -ie, constraint-sets formed by constraints whose form is either α ≤ s or s ≤ α-whose set of solutions is sound and complete w.r.t. the constraint t ≤ 0. This function is parametric in a set M of visited types (needed to handle coinduction) and the algorithm to compute it is given in Figure 3. If the input type t is not in normal form, then the algorithm is applied to the disjunctive normal form t ′ of t (end of line 6). Since a union is empty if and only if every summand that composes it is empty, then the algorithm generates a new constraint-set for the problem that equates all the summands of a normal form to 0 (beginning of line 6). If a summand contains a top-level variable, then the smallest (wrt ) top-level variable is singled out (line 2). If there is no top-level variable and there are only basic types, then the algorithm checks the constraint by calling the subtyping algorithm and, accordingly, it returns either the unsatisfiable set of constraint-sets (∅) or the one that is always satisfied ({∅}) (line 3). Finally, if there are only intersections of arrows and their negations, then the problem is decomposed into a set of subproblems by using the decomposition rule of the subtyping algorithm for semantic subtyping (see [START_REF] Frisch | Semantic subtyping: dealing set-theoretically with function, union, intersection, and negation types[END_REF] for details), after having added t to the set M of visited types. The regularity of types ensures that the algorithm always terminates (see Lemma C.14). Notice that, in line 2 the algorithm always singles out the smallest variable. Therefore, by construction, if norm generates a constraint (α, t) or (t, α), then every variable smaller than or equal to α may occur in t only under an arrow (equivalently, every top-level variable of t is strictly larger than α). REMARK 3.1. There is the special case of (α, t) or (t, α) in which t is itself a variable. In that case we give priority to the smallest variable and consider the larger variable be a bound for the lower one but not vice-versa. This point will be important for merge.

A constraint-set in which all constraints satisfy this property is said to be well ordered (cf. Definition C.16).

EXAMPLE (Cont'd).

The function norm works on single constraints (actually, on a type t representing the constraint t ≤ 0), so let us apply it on the first constraint of the example. We want to normalize the constraint α→Bool ≤ β→β, and thus we apply norm to the type (α→Bool) ∧ ¬(β→β). Now, this constraint has two distinct solutions: either (i) β is the empty set, in which case the larger type becomes 0→0 that is the type of all functions (see Footnote 3) which contains every arrow type, in particular α→Bool, or (ii) the types satisfy the usual covariantcontravariant rule for arrows, that is, β ≤ α and Bool ≤ β. Since there are two distinct solutions, then norm generates a set of two constraint-sets. Precisely norm((α→Bool) ∧ ¬(β→β), ∅) returns { { (β, 0) } , { (β, α) , (Bool, β) } }. Both constraint-sets are normalized and are computed by Line 5 in Figure 3: the first constraint-set is computed by the rightmost recursive call of norm (notice that P ′ =∅ -since it ranges over the strict subsets of P which, in this case, is a singleton-so it requires sn, ie β, to be empty), while the second constraint-set is obtained by the union of the first two recursive calls (which require sn ≤ sp and tp ≤ tn).

Constraint merging.

Take a normalized constraint-set. Each constraint of this set isolates one particular variable. However, the same variable can be isolated by several distinct constraints in the set. We next want to transform this constraint-set into an equivalent one (ie, a constraint-set with exactly the same set of solutions) in which every variable is isolated in at most two constraints, one where the variable is on the left-hand side and the other where it is on the right-hand side. In other words, we want to obtain a normalized constraint-set in which each variable has at most one upper bound and at most one lower bound. In practice, this set represents a set of constraints of the form { si≤αi≤ti | i ∈ I } where the αi's are pairwise distinct. This is done by the function merge(C, M ) where C is a normalized constraint-set and M a set containing the types already visited by the function. The function merge performs two steps. In the first step it scans (using so as to give priority to smaller variables, cf. Remark 3.1) the variables isolated by the normalized constraint-set C and for each such variable it merges all the constraints by taking the union of all its lower bounds and the intersection of all its upper bounds. For instance, if C contains the following five constraints for α: (s1, α), (s2, α), (α, t1), (α, t2), (α, t3), then the first step replaces them by (s1∨s2, α) and (α, t1∧t2∧t3), which corresponds to having the constraint s1∨s2 ≤ α ≤ t1∧t2∧t3. Such a constraint is satisfiable only if the constraint that the lower bound of α is smaller than its upper bound is satisfiable. This is checked in the second step, which looks for pairs of constraints of the form (s, α) and (α, t) (thanks to the first step we know that for each variable there is at most one such pair) and then adds the constraint (s, t) to C. This constraint is equivalent to (s∧¬t, 0) but neither it or (s, t) is normalized. Thus before adding it to C we normalize it by calling norm(s∧¬t, ∅). Recall that norm returns a set of constraint-sets, each constraint-set corresponding to a distinct solution. So we add the constraints that are in C to all the constraint-sets that are the result of norm(s∧¬t, ∅) via the ⊓ operator (this is why merge returns a set of constraint-sets rather than a single one). The constraint-sets so obtained are normalized but they may be not merged, yet. So we recursively apply merge to all of them (via the operator ⊔) and we record s∧¬t in M . Of course, this step 2 is done only if the constraint (s, t) was not already embedded in C before, that is, only if s∧¬t is not already in M . Note that merge preserves the property that in every constraint (α, t) or (t, α), every variable smaller than or equal to α may occur in t only under an arrow.

EXAMPLE (Cont'd).

If we apply norm also to the second constraint of our example we obtain a second set of constraint-sets: { { (α, 0) } , { (α, Int∨Bool) , (Int, β) } }. To obtain a sound and complete set of solutions for our initial C we have to consider all the possible combinations (see Step 1 of the constraint solving algorithm later on) of the two sets obtained by normalizing C, that is, a set of four constraint-sets:

{ { (α, 0), (β, 0) } , { (α, Int∨Bool) , (Int, β) , (β, 0) } , { (Bool, β) , (β, α) , (α, 0) } , { (Bool, β) , (Int, β) , (β, α) , (α, Int∨Bool) } } The application of merge to the first set leaves it unchanged. Merge on the second one returns an empty set of constraint-sets since at the second step it tries to solve Int ≤ 0. The same happens for the third since it first adds β ≤ 0 and at the recursive call tries to solve Bool ≤ 0. The fourth one is more interesting: in step 1 it replaces (Bool, β) and (Int, β) by (Int∨Bool, β) and at the second step adds (β, Int∨Bool) obtained from (β, α) and (α, Int∨Bool) (it also checks (Int∨Bool, Int∨Bool) which is always satisfied). So after merge we have { {(α,0) , (β,0)} , { (β, α) , (α, Int∨Bool) , (Int∨Bool, β) , (β, Int∨Bool) } }. Notice that we did not merge (β, α) and (β, Int∨Bool) into (β, α∧(Int∨Bool)): since α β, then α is not considered an upper bound of β (see Remark 3.1) and thanks to that the resulting constraint-set is well ordered.

3. Constraint solving. norm and merge yield a set in which every constraint-set is of the form C = {si≤αi≤ti | i ∈ I} where αi are pairwise distinct variables and si and ti are respectively 0 or 1 whenever the corresponding constraint is absent. If there is a constraint on two variables, then again priority is given to the smaller variable. For instance, if α β, then {(α, β)} will be considered to represent {(0≤α≤β), (0≤β≤1)}. Thanks to this assumption the system so obtained is well ordered, that is, for every constraint s≤α≤t in it, the top-level variables of s and t are strictly larger than α. Notice that in doing that we do not lose any information: the bounds for larger variables are still recorded in those of smaller ones and any bound for larger variables obtained by transitivity on the smaller variables is already in the system by step 2 of merge.

The last step is to solve this constraint-set, that is, to transform it into a solvable set of equations that then we solve by a Unify algorithm that exploits the particular form of the equations obtained from a well-ordered constraint-set. Let C be a well-ordered constraint-set of the above form; we define solve(C) as follows:

solve(C) = {α = (s ∨ β) ∧ t | (s ≤ α ≤ t) ∈ C, β fresh}
The function solve(C) takes every constraint s ≤ α ≤ t in C and replaces it by α = (s ∨ β) ∧ t (with β fresh). It is clear that the constraint-set C has a solution for every possible assignment of α included between s and t if and only if the new constraint-set has a solution for every possible (unconstrained) assignment of β. At the end, the constraint-set {si≤αi≤ti | i ∈ I} has become a set of equations of the form {αi = ui | i ∈ I} where the αi's are pairwise distinct. By construction, this set of equations has the property that every variable that is smaller than or equal to (wrt ) αi may occur in ui only under an arrow (as for constraint-sets we say that the set of equations is well ordered). This last property ensures the contractivity of the equation defining the smallest type variable. By Courcelle [START_REF] Courcelle | Fundamental properties of infinite trees[END_REF] (and Lemma C.44) there exists a solution of this set, namely, a substitution from the type variables α1, ..., αn into (possibly recursive regular) types t1, ..., tn whose variables are contained in the fresh βi's variables introduced by solve (all universally quantified, ie, no upper or lower bound) and the type variables in ∆. This solution is given by the following Unify procedure in which we use µ-notation to denote regular types and where E is a well-ordered set of equations.

Unify(E)= if E = ∅ then return {} else -select in E the equation α = tα for the smallest α (wrt )
-let E ′ be the set of equations obtained by replacing in E\{α = tα} every occurrence of α by µX.(tα{ X / α }) (X fresh) -let σ = Unify(E ′ ) in return {α = (µX.tα{ X / α })σ} ∪ σ Thanks to the well-ordering of E, Unify generates a set of solutions in which all types satisfy the contractivity condition on infinite branches of Definition 2.1. It solves the (contractive) recursive equation of the smallest variable α defined by E (if α does not occur in tα, then the µ-abstraction can be omitted), replaces this solution in the remaining equations, solves this set of equations, and applies the solution so found to the solution of α so as to solve the other variables occurring in its definition.

The complete algorithm.

The algorithm to solve the tallying problem for C and variables not in ∆, then, proceeds in three steps:

Step 1. Let N = (s,t)∈C norm(s∧¬t, ∅). If N = ∅ then fail else proceed to the next step.

Step 2. Let M = C∈N merge(C, ∅). If M = ∅ then fail else proceed to the next step.

Step 3.

Let S = C∈M solve(C). Return {Unify(E) | E∈S }.
Let Sol∆(C) denote the set of all substitutions obtained by the previous algorithm. They form a sound and complete set of solutions for the tallying problem: Theorem 3.6 (Soundness and completeness).

σ ∈ Sol∆(C) ⇒ σ ∆ C σ ∆ C ⇒ ∃σ ′ ∈ Sol∆(C), σ ′′ , s.t. σ ≈ σ ′′ • σ ′
where ≈ means that the two substitutions map the same variable into equivalent types. Regularity of types ensures the termination of the algorithm and, hence, the decidability of the tallying problem (the proof of these properties combines proofs of soundness, completeness, and termination of each step: see Appendix C).

EXAMPLE (End). After

Step 1 and 2 our initial tallying problem

{(α→Bool, β→β) , (Int∨Bool → Int , α→β)} has become { {(α,0) , (β,0)} , { (β, α) , (α, Int∨Bool) , (Int∨Bool, β) , (β, Int∨Bool) } }.
Let us apply Step 3. The first constraint-set is trivial and it is easy to see that it yields the solution { 0 / α , 0 / β }. The second constraint-set is { (β≤α≤Int∨Bool) , (Int∨Bool≤β ≤ Int∨Bool) }. We apply solve to the constraints for α obtaining {α = (γ∨β)∧(Int∨Bool)}. We find the solution for β (no need to substitute α since it does not occur in the constraints for β) which is {β = Int∨Bool}. We replace β in the solution of α obtaining {α = (γ∨Int∨Bool)∧(Int∨Bool)}. The solution for this second constraint-set is then { Int∨Bool / α , Int∨Bool / β }, which with { 0 / α , 0 / β } forms a sound and complete set of solutions for our initial tallying problem.

Finally, solve introduces several fresh polymorphic variables which can be cleaned up after that the substitutions have been applied to obtain the types deduced by inference system: all variables that occur only in covariant (resp. contravariant) position in a type, can be replaced by 0 (resp. 1). This is what we implicitly did in our example to solve β and eliminate γ from the constraint of α.

Solution for application with fixed cardinalities

It remains to solve the problem for the (INF-APPL) rule. We recall that given two types s and t, a solution for this problem is a pair of sets of type-substitutions [σi]i∈I , [σj]j∈J for variables not in ∆ that make both of these two inequations

i∈I tσi ≤ 0→1 j∈J sσj ≤ dom( i∈I tσi) (15)
hold. Two complications are to be dealt with: (i) we must find sets of type substitutions, rather than a single substitution as in the tallying problem and (ii) we have to get rid of the dom() function. If I and J have fixed cardinalities, then both difficulties can be easily surmounted and the whole problem be reduced to a tallying problem. To see how, consider the two inequations in [START_REF] Kfoury | Principality and decidable type inference for finite-rank intersection types[END_REF]. Since the two sets of substitutions are independent, then without loss of generality we can split each substitution σ k (for k∈I∪J) in two substitutions: a renaming substitution ρ k that maps each variable in the domain of σ k into a different fresh variable, and a second substitution

σ ′ k defined such that σ k = σ ′ k • ρ k . The two inequations thus become i∈I (tρi)σ ′ i ≤ 0→1 and j∈J (sρj)σ ′ j ≤ dom( i∈I (tρi)σ ′ i ).

Since the various σ ′

k (for k ∈ I∪J) have disjoint domains, then we can take their union to get a single substitution σ = k∈I∪J σ ′ k , and the two inequations respectively become ( i∈I tρi)σ ≤ 0→1 and ( j∈J sρj)σ ≤ dom(( i∈I tρi)σ). Now if we fix the cardinalities of I and J since the ρ k are generic renamings, we have just transformed the problem in [START_REF] Kfoury | Principality and decidable type inference for finite-rank intersection types[END_REF] into the problem of finding for two given types t1 and t2 all substitutions σ such that 6t1σ ≤ 0→1 and t2σ ≤ dom(t1σ) (16) hold. Finally, we can prove (see Lemmas C.49 and C.50) that a type-substitution σ solves [START_REF] Leivant | Polymorphic type inference[END_REF] if and only if it solves t1σ ≤ 0→1 and t1σ ≤ (t2→γ)σ (17) with γ fresh. We transformed the application problem (with fixed cardinalities) into the tallying problem for {(t1, 0→1), (t1, t2→γ)}, whose set of solutions is a sound and complete set of solutions for the (INF-APPL) rule problem when I and J have fixed cardinalities.

Solution of the application problem

The algorithm to solve the general problem for the (INF-APPL) rule explores all the possible combinations of the cardinalities of I and J by, say, a dove-tail order. More precisely, we start with both I and J at cardinality 1 and:

Step A: Generate the constraint-set {(t1, t2→γ)} as explained in Subsection 3.2.2 (the constraint t1≤0→1 is implied by this one since 0→1 contains every arrow type) and apply the tallying algorithm described in Subsection 3.2.1, yielding either a solution (a substitution for variables not in ∆) or a failure.

Step B: If all the constraint-sets failed at Step 1 of the algorithm of Subsection 3.2.1, then fail (the expression is not typeable). If they all failed but at least one did not fail in Step 1, then increase the cardinalities of I and J to their successor in the dove-tail order and start from Step A again. Otherwise all substitutions found by the algorithm are solutions of the application problem.

Notice that the algorithm returns a failure only if all the constraintsets fail at Step 1 of the algorithm for the tallying problem. The reason is that up to Step 1 all the constraints at issue are on distinct occurrences of type variables: if they fail, there is no possible expansion that can make the constraint-set satisfiable. In Step 2, instead, constraints of different occurrences of some variable are merged. Thus even if the constraints fail, it may be the case that they will be satisfied by expanding different occurrences of some variable into different variables. Therefore an expansion is tried. Solving the problem for s ⊑∆ t is similar (there is just one set whose cardinality has to be increased at each step instead of two).

This constitutes a sound and complete semi-decision procedure for the application problem and, thus, for the type-substitution inference system (Theorem C.54). We defined some heuristics (omitted for space reasons: see Section C.2.3) to stop the algorithm when a solution seems unlikely. Whether these (or some coarser) halting conditions preserve completeness, that is, whether typesubstitutions inference is decidable, is an open problem. We believe the system to be decidable. However, we fail to prove it when the type of the argument of an application is a union: its expansion distributes the union over the intersections thus generating new combinations of types. It comes as no surprise that the definitions of our heuristics are based on the cardinalities and depths of the unions occurring in the argument type.

Let us apply the algorithm to map even. We start with the constraint set {(α1→β1)→[α1]→[β1] ≤ t→γ} where t = (Int→Bool)∧(α\Int→α\Int) is the type of even (we just renamed the variables of the type of map). After Step A the algorithm generates a set of nine constraint-sets (see Section 10.2.2 of [START_REF] Xu | Parametric Polymorphism for XML Processing Languages[END_REF] for more details on this example): one is unsatisfiable since it contains the constraint t ≤ 0 (an intersection of arrows is never empty since it always contains 1→0 the type of the diverging functions); four of these are less general than some other (their solutions are included in the solutions of the other) and the remaining four are obtained by adding the constraint γ ≥ [α1]→[β1] respectively to {α1≤0}, {α1≤Int, Bool≤β1}, {α1≤α\Int, α\Int≤β1}, {α1≤α∨Int, (α\Int)∨Bool≤β1}, yielding the following four solutions for γ:

{γ=[]→[]}, or {γ = [Int]→[Bool]}, or {γ = [α\Int]→[α\Int]}, or {γ = [α∨Int]→[(α\Int)∨Bool]}.
Of these solutions only the last two are minimal. Since both are valid we could stop here and take their intersection, yielding the type expected in the introduction. If instead we strictly follow the algorithm, then we have to perform a further iteration, expand the type of the function, yielding

{((α1→β1)→[α1]→[β1])∧((α2→β2)→[α2]→[β2]) ≤ t→γ} for which the minimal solution is, as expected: {γ = ([α\Int]→[α\Int]) ∧ ([α∨Int]→[(α\Int)∨Bool])}
A final remark on completeness. The theorem states that for every solution of the inference problem, our algorithm finds a solution that is more general. However this solution is not necessary the first one found by the algorithm: even if we find a solution, continuing with a further expansion may yield a more general solution. We have just seen that in the case of map even the good solution is the second one, although this solution could already have been deduced by intersecting the first minimal solutions we found. A simple example that shows that carrying on after a first solution may yield a better solution is the application of a function of type (α × β) → (β × α) to an argument of type (Int×Bool) ∨ (Bool×Int). For this applications our algorithm (extended with product types) returns after one iteration the type (Int∨Bool) × (Int∨Bool) (since it unifies α with β) while one further iteration would deduce the more precise type (Int×Bool) ∨ (Bool×Int). Of course this raises the problem of the existence of principal types (notice that the type t ′ in the statement of Theorem 3.3 is not unique): may an infinite sequence of increasingly general solutions exist? This is a problem we did not tackle in this work, but if the answer to the previous question were negative, then it would be easy to prove the existence of a principal type: since at each iteration there are only finitely many solutions, then the principal type would be the intersection of the minimal solutions of the last iteration.

Finally, notice that we did not give any reduction semantics for the implicitly-typed calculus. The reason is that its semantics is defined in terms of the semantics of the explicitly-typed calculus: the relabeling at run-time is an essential feature -independently from the fact that we started from an explicitly-typed expression or not-and we cannot avoid it. If we denote by erase -1 (a) the set of expressions e that satisfy the statement of Theorem 3.2, then the (big-step) semantics for an implicitly-typed expression a is given in terms of erase -1 (a): if an expression in erase -1 (a) reduces to v, so does a. As we see the result of computing an implicitly-typed expression is a value of the explicitly-typed calculus (so λ-abstractions may contain non-empty decorations) and this is unavoidable since it may be the result of a partial application (this can be made transparent for the programmer by returning just the type and the "value" <fun> as in OCaml's toplevel). Also notice that the semantics is not univocally determined since different expressions in erase -1 (a) may yield different results. However this may happen only in one particular case, namely, when an occurrence of a polymorphic function flows into a type-case and its type is tested. For instance the application (λ (Int→Int)→Bool f.f ∈Bool→Bool ? true : false)(λ α→α x.x) results into true or false according to whether the polymorphic identity at the argument is instantiated by

[{ Int / α }] or by [{ Int / α }, { Bool / α }].
Once more this is unavoidable in a calculus that can dynamically test the types of polymorphic functions that admit several sound instantiations. This does not happen in practice since the inference algorithm always choose one particular instantiation (the existence of principal types would make this choice canonical and remove any residual latitude). So in practice the semantics is deterministic but implementation dependent.

In summary, programming in the implicitly-typed calculus corresponds to programming in the explicitly-typed one with the difference that we delegate to the system the task to write typesubstitutions for us and with the caveat that by doing that we make the dynamic test of the type of a polymorphic function to be implementation dependent. Of course, forbidding the dynamic test of the type of polymorphic functions (or of functions tout court) make this problem disappear (and yields much a simpler implementation).

Examples and experiments

We developed two implementations (see the last page of the appendix for download instructions), a complete but non-optimized prototype with products and arrow type constructors, and an extension of the full CDuce language which is highly optimized (types are stored in hash-consed binary decision trees to avoid the cost of normalization, pattern-matching has optimal implementation, static analyses are used to minimize the impact of polymorphism and so on). In this section we show examples of the latter, that is of CDuce syntax extended with type variables. 7 In this extension map has type (α→β)→[α*]→[β*] since in CDuce sequence types are denoted by brackets whose content is described by a regular expression on types. Functions are explicitly typed and thus must specify both their input and output types let pretty (x: Int): String = string_of x or the whole interface when they are typed by an intersection type:

let even (Int -> Bool ; (α\Int) -> (α\Int)) | x & Int -> (x mod 2) = 0 | x -> x
The type returned for the partial application map even is then

([(α\Int)*]→[(α\Int)*])&([(α|Int)*]→[(α\Int|Bool)*])
(unions and intersections are denoted by | and &, respectively) while the one for map pretty is

([]→[])&([Int*]->[String*]).
While the right-hand side arrow of this intersection is the type an ML programmer would expect, our inference algorithm also deduces the special case []→[], stating that the function maps the empty list into itself. Interestingly, the solver does not need to know the body of map to deduce it; this is because CDuce encodes lists by recursive union types ([α*] stands for µX.nil∨(α, X) where nil denotes the empty list) and our system tries to infer a result for every type in the union. Instantiation works as expected as the following snippet of CDuce interactive toplevel shows ("#" is the prompt of the toplevel while its output is displayed in italics):

# let g ((Int -> Int) -> Int -> Int ; (Bool -> Bool) -> Bool -> Bool) x -> x;; val g : (Bool -> Bool) -> Bool -> Bool & (Int -> Int) -> Int -> Int = <fun> # let id ('a -> 'a) x -> x;; val id : 'a -> 'a = <fun> # g id;; -: (Bool -> Bool) & (Int -> Int) = <fun> # id (id g) ;; -: (Bool -> Bool) -> Bool -> Bool & (Int -> Int) -> Int -> Int = <fun>
Our system includes singleton types (types that contain a single value) and thus the type returned, for instance, for let churchtrue (x: α)(y: β): α = x in churchtrue 42;; is β → 42 (ie, the type of functions that accept any argument and return 42) and, likewise, id 42 has type 42. More surprising may be the case for a function such as max (whose definition uses the CDuce's polymorphic comparison operator >> "greater than"):

# let max (x: α)(y: α): α = if (x >> y) then x else y;; val max : α -> α -> α = <fun>
An ML programmer would probably expect the partial application max 42 to be typed as 42→42 or Int→Int (at least, we were naively expecting that). Instead, for this application the system returns the type (β|42)→(β|42), and rightly so. The point is that our system includes union types and, therefore, an application such as max 42 "3" is well typed: it suffices to instantiate the variable α in the type of max by the union type Int|String. To give the final instantiation for α the type system must know the type of both arguments of max, therefore in the case of the partial application, it instantiates α with β|42 stating that it knows that α contains at least the value 42 and waits for the second argument to instantiate the missing part, represented by β; and the type returned for max 42 "3" is 42|"3". In this example we specified the type α->α->α for max, since this is what an ML programmer would have written. However, in a system with polymorphic union types a more meaningful type for max is α->β->α|β: if we specify such a type for max, then the type deduced for the partial application max 42 is, more intuitively, β->(β|42). The fact that α->β->α|β and α->α->α cannot, from any practical point of view, be distinguished seems a nice feature of our system. Nevertheless notice that the same type deduction as for max would have happened if in the definition of churchtrue we had used α instead of β; in that case churchtrue 42 "3" would have been typed by the (less precise) union type 42|"3", too. Thus, in order to achieve precise typing, it is important to use distinct type variables for distinct parameters. Finally, we said in the introduction that the typing of even follows a pattern that is common in programming functional data structures. This can be seen by examining Okasaki's implementation of red-black trees [START_REF] Okasaki | Purely Functional Data Structures[END_REF]. These are balanced binary search trees whose nodes are colored either in black or in red and such that every red node has two (possibly empty) black children; a red node with a red child is a "wrong" tree. Insertions must keep the tree balanced and the key definition is a function balance which transforms every "unbalanced" tree -ie, a black-rooted tree with a "wrong" child-into a red-rooted tree, and leaves all other trees unchanged. Okasaki gives a very compact and elegant definition of balance consisting of a pattern matching with two cases (for a union and for a capture variable), but current type systems are not expressive enough to verify that his code, without any modification, satisfies color invariants. Our types, instead, can do it as follows:

type RBtree = Btree | Rtree type Btree = <blk elem=α>[ RBtree RBtree ] | [] type Rtree = <red elem=α>[ Btree Btree ] type Unbal = <blk elem=α>( [ Wrong RBtree ] | [ RBtree Wrong ]) type Wrong = <red elem=α>( [ Rtree Btree ] | [ Btree Rtree ]) let balance ( Unbal -> Rtree ; (β\Unbal) -> (β\Unbal) ) | <blk (z)>[ <red (y)>[ <red (x)>[ a b ] c ] d ] | <blk (z)>[ <red (x)>[ a <red (y)>[ b c ] ] d ] | <blk (x)>[ a <red (z)>[ <red (y)>[ b c ] d ] ] | <blk (x)>[ a <red (y)>[ b <red (z)>[ c d ] ] ] -> <red (y)>[ <blk (x)>[ a b ] <blk (z)>[ c d ] ] | x -> x
The only (irrelevant) difference of this definition with Okasaki's definition of balance is that we used CDuce's syntax for trees, that is, XML elements tagged by their color, with an attribute elem for their content, and that delimit sequences of two sub-trees. The type of balance (which has the same form as the type of even) precisely describes the behavior of the function and this type information is enough to prove that the insertion function has type α→Btree→Btree, that is, that when it inserts an α-element into a well-formed black-rooted red-black it returns another well-formed black-rooted red-black tree (see Appendix A for the complete code and how to run it on the development version of CDuce).

Transposing the results and algorithms of this paper, to fullfledged CDuce was not easy. Adapting the internal representation of types and its algorithms is challenging (to give an idea of such a challenge, consider that a simple type variable is internally represented as a hash-consed union of 7 binary decision diagrams each intersecting the top type of a type constructor) and so are type pretty printing and error message generation. For what is specific to this work, the main challenge is not only to extend the typing rules of Figure 2 to missing data structures and expressions (XML trees, general pattern matching, products, ...) but, above all, to modify the rules so that they return expressions decorated with sets of explicit types substitutions. Also the various internal languages used by the compiler must be modified (the CDuce compiler performs several passes that translate each intermediate language into a lower level one) and each transformation phase must be enriched with specific static analyses to optimize the evaluation of polymorphic expres-sions. Finally, the propagation of type substitutions must be lazily implemented for all constructed values (ie, pairs and XML documents). The main modifications are summarized in Appendix E.

For what concerns performances, the results of some preliminary experiments are reported in Appendix F. In summary, we generated a test suite of 1 859 applications of higher-order polymorphic functions by taking all the 43 functions exported by the List module of OCaml, and cross applying one to each other. Whenever a given function can be applied (ie, the application type-checks in OCaml) to two other functions, then we applied it to their intersection and their union; whenever two functions can be applied to the same function then we applied their union and their intersection to it; and so on so forth up to a maximum of 15 top-level connectives. We also tested all applications resulting ill-typed in OCaml, so as to check cases in which local type-inference may fail. The results are significant and encouraging. The test suite was defined to maximize the possible exponential blow up (which is essentially due to the presence of arrows and intersections that may trigger multiple expansions). The combinations of the functions of the List module cover a wide range of use cases and involve recursive types (specifically, polymorphic lists), and the limit of 15 connectives on arrows more than doubles what we ever met in practice. To type check the 1 859 applications on an average laptop took 27 secs with an average time for application of 14ms and 2.1ms of median time. This means that apart from few pathological cases (which took a couple of seconds) our implementation performs local type inference within acceptable delays. We also verified that our implementation smoothly handles the application of curried functions to 20 arguments (cf., OCaml standard library whose functions have at most 5 arguments). Furthermore, the room for improvement is still important. Our implementation uses the highly-optimized data-structures of CDuce types and aggressive memoization, however normalization and constraint generation are implemented as described in this paper. In particular, as in Line 5 in Figure 3, normalization performs a full expansion. By modifying the algorithms so that, like in the subtyping algorithm, normalization and constraint generation are performed lazily, we hope to improve performance by an order of magnitude.

Type reconstruction

The theory of type tallying we developed in Section 3 can be reused to perform type reconstruction, that is, to assign a type to functions whose interface is not specified. The idea is to type the body of a function under the hypothesis that the function has the generic type α→β and deduce the corresponding constraints. Formally, we consider expressions produced by the following grammar:

m ::= c | x | mm | λx.m | m∈t ? m : m together with the judgment Γ ⊢ R m : t
S that states that under the typing environment Γ, m has type t under the constraints in S , provided that S is satisfiable (the turnstile subscript R indicates that this is a type Reconstruction system). These judgments are derived by the rules in Figure 4. These are quite standard apart from the fact that they derive multiple constraint-sets, rather than just one. This is due to the type reconstruction rule for type-cases, which explores four possible alternatives (m0 diverges, it can match only the first, the second, or both cases). In this system the type of a well-typed expression is a type and a set of type-substitutions (ie, the set of all substitutions that are solutions of the satisfiable constraint-sets in S ) and thus it is an intersection type obtained by applying this set of type-substitutions to the type.

The soundness of this system is a consequence of the results on the type-substitution inference of the previous sections. As a matter of facts, this system is precisely the same system as the one in the previous sections with the only difference that all interfaces are of the form α→β and, to compensate that, we infer type-substitutions in decorations (we also used a different and more standard presentation to stress constraint generation). Of course, completeness does not hold: far from that. For instance, it is impossible, in general, to deduce for a function without type annotations the type 1→0the type of all diverging functions-since this would correspond to decide the halting problem (though our algorithm returns for µf x=f (x) the same type as in ML, that is, α→β). Likewise, completeness would imply decidability of reconstruction and thus imply decidability for intersection type systems, which are undecidable. Similarly, our reconstruction system cannot type the paradoxical functions we pointed out in the first part of this work (see Section 2 in [START_REF] Castagna | Polymorphic functions with set-theoretic types. Part 1: Syntax, semantics, and evaluation[END_REF]). However, if a function can be typed in ML-like type systems, then our type reconstruction rules can deduce a type at least as good as the ML one. Indeed, if we restrict our attention to the first four rules, the system produces a singleton set of constraints that is the same as in ML system (cf. [START_REF] Pottier | The essence of ML type inference[END_REF]) and when constraintsets are not circular (ie, their solution does not require recursive types), then our constraint solving algorithm coincides with unification (all fresh variables introduced by solve are simplified as we described at the end of Section 3.2.1 and solve directly produces a set of equations that are, in Martelli and Montanari's terminology [START_REF] Martelli | An efficient unification algorithm[END_REF], in solved form). Furthermore, since the types considered here are much richer than in ML (since they include unions, intersections, and negations), then our reconstruction may infer slightly better types. Type connectives alone bring, in particular, two advantages for type reconstruction: (i) the system deduces sets of typesubstitutions (and thus deduces intersection types) and (ii) pattern matching (which can be seen as a type-case with singleton types) is typed more precisely (thanks in particular to intersections and negations). For instance, and contrary to ML, our type reconstruction can type auto-application λx.xx for which it returns the recursive type t = µX.(α∧(X→β)) → β. This type is a subtype of -thus, it is more precise than-the classic (non-recursive) typing of autoapplication in intersection type systems t ≤ (α∧(α→β)) → β (though it is not as precise as its subtype µX.(α∨(X→β)) → β which can also type auto-application). As a final example, if we apply our type reconstruction algorithm (extended with products and recursive functions) to the type erasure of the map function defined in equation ( 12), then we obtain the type (in CDuce's syntax)

((α→β) → [α*]→[β*]) ∧ ((0→1) → []→[]) (
see the complete unfolding of the algorithm in Appendix D). Thanks to the precise typing of the type-case, our type is slightly more accurate than the ML type, since it states that the application of map to any function and the empty list returns the empty list.

Finally, the "type" returned by the type reconstruction algorithm is not always very readable and often needs to be simplified. For instance, the type we showed for map was obtained after apply-ing some simplifications -one of which was done by hand-, and defining an algorithm that does the right simplifications is not obvious (eg, how to detect that the type (α∧(α→β))→β is much more readable than the type µX.(α∧(X→β))→β reconstructed for auto-application by our algorithm?). The simplification of types (or of type constraints) is a stand alone research topic that deserves further investigation. Nevertheless our reconstruction algorithm can already be used as is, to make type declaration of local functions optional. Indeed for local functions the system is not required to return a "readable" type to the programmer, but just to check whether there exists a typing for local functions that is compatible with their usage; and, for that, our system is enough, even though we will probably have to couple it with bidirectional typing techniques [START_REF] Davies | Practical Refiniment-Type Checking[END_REF] to provide informative error messages when the check fails.

Extensions

In this presentation we omitted two key features: pairs and recursive functions. Recursive functions do not pose any particular problem in the inference of type-substitutions and are dealt with in a standard way, while pairs are more challenging. The rule for pairs in inference system ⊢ I is the same as in the explicitly-typed calculus (this corresponds to disregarding sets of type-substitutions applied inside a pair, as they can equivalently be inferred outside the pair: ti ≃ 0 and (t1×t2) ⊑∆ (s1×s2) ⇔ ti ⊑∆ si). Instead, as expected, the rule for projection πie needs some special care since if the type inferred for e is, say, t, then we need to find a set of substitutions [σi]i∈I such that i∈I tσi ≤ 1×1. This problem can be solved by using the very same technique we introduced for •∆, namely by solving a sequence of tallying problems generated by increasing at each step the cardinality of I (see the appendix).

In the first part of this work [START_REF] Castagna | Polymorphic functions with set-theoretic types. Part 1: Syntax, semantics, and evaluation[END_REF] we studied the extension of the explicitly-typed calculus with let-polymorphism, in particular, its typing and efficient execution (see Section 5.4 of [START_REF] Castagna | Polymorphic functions with set-theoretic types. Part 1: Syntax, semantics, and evaluation[END_REF]). There we distinguished let-bound variables by underlining them. Reconstruction is mostly useful when combined with let-polymorphism. To extend our reconstruction to let we use a separate type environment Φ for these variables (while we reserve Γ for λ-abstracted variables). As in Damas-Milner W algorithm [START_REF] Damas | Principal type-schemes for functional programs[END_REF] we need to define Γ(t), the generalization (closure in [START_REF] Damas | Principal type-schemes for functional programs[END_REF]) of a type t wrt the type environment Γ, that is, Γ(t)

def = t[{ γ i/ α i | αi ∈ var(t)\var(Γ)}]
where γi are fresh. Then the rules for type reconstruction are

(let-var) Φ ; Γ ⊢ R x : Γ(Φ(x)) {∅} (let) Φ ; Γ ⊢ R e1 : t1 S Φ, (x : t1) ; Γ ⊢ R e2 : t2 S ′ Φ ; Γ ⊢ R let x = e1 in e2 : t2 S ⊓ S ′
Finally, we want to stress that there is at least a case in which we should have been more restrictive, that is, when an expression that is tested in a type-case has a polymorphic type. Our inference system may type it (by deducing a set of type-substitutions that makes it closed), even if this seems to go against the intuition: we are testing whether a polymorphic expression has a closed type. Although completeness ensures that in some cases it can be done, in practice it seems reasonable to consider ill-typed any type-case in which the tested expression has a polymorphic type (see Section B.3).

Related work

This section discusses related work on constraint-based type inference and inference for intersection/union type systems. Discussion about work on explicitly-typed intersection type systems and on XML processing languages can be found in Part 1 of this work [START_REF] Castagna | Polymorphic functions with set-theoretic types. Part 1: Syntax, semantics, and evaluation[END_REF].

Type inference in ML has essentially been considered as a constraint solving problem [START_REF] Odersky | Type inference with constrained types[END_REF][START_REF] Pottier | The essence of ML type inference[END_REF]. We use a similar approach to solve the problem of type unification: finding a proper substitution that makes the type of the domain of a function compatible with (ie, a supertype of) the type of the argument it is applied to. Our type unification problem is essentially a specific set constraint problem [START_REF] Aiken | Type inclusion constraints and type inference[END_REF]. This is applied in a much more complex setting with a complete set of type connectives and a rich set-theoretic subtyping relation. In particular, because of the presence of intersection types, solving the problem of application demands to find sets of substitutions rather than just one substitution. This is reflected by the definition of our ⊑ relation which is much more thorough than the corresponding relation used in ML inference insofar as it encompasses instantiation, expansion, and subtyping. The important novelty of our work comes from the use of set-theoretic connectives, which allows us to turn sets of constraints of the form s≤α≤t into sets of equations of the form α = (β ∨ s) ∧ t, a technique that, in our ken, is original to our work. This set of equations is then solved using Courcelle's work on infinite trees [START_REF] Courcelle | Fundamental properties of infinite trees[END_REF]. The use of type connectives also implies that we solve multiple sets of constraints, which account for different alternatives. Finally, it is worth noticing that [START_REF] Odersky | Type inference with constrained types[END_REF][START_REF] Pottier | The essence of ML type inference[END_REF] use a richer language of constraints that includes binding. This allows separating constraint generation and constraint solving without compromising efficiency. Therefore an interesting direction of future research is either to re-frame our work into a richer language of constraints or to extend the work in [START_REF] Odersky | Type inference with constrained types[END_REF][START_REF] Pottier | The essence of ML type inference[END_REF] to encompass our richer setting. This could be a first step towards the study of efficient constraint solving algorithms for our system.

Feature-wise the programming language closest to our language -ie, polymorphic CDuce-is Typed Racket [START_REF] Tobin-Hochstadt | The design and implementation of typed scheme[END_REF][START_REF] Tobin-Hochstadt | Logical types for untyped languages[END_REF] since it has recursive types, union types, top and singleton types, subtyping, dynamic type-cases (called occurrence typing in [START_REF] Tobin-Hochstadt | The design and implementation of typed scheme[END_REF][START_REF] Tobin-Hochstadt | Logical types for untyped languages[END_REF]), and explicitly-typed polymorphic functions. The goal of Typed Racket is to type an existing untyped programming language and it is superior to our system in that it allows the combination of both typed and untyped code in a single program. For what concerns typed features, however, Typed Racket is just a small fragment of our system: type-cases can only test basic types and tests for just some constructed types can be encoded by using Boolean connectives; there are no intersection types (thus, no overloaded functions); there are no negation or difference types; union types and their subtyping are quite naive (eg, a type is a subtype of a union of types only if it is a subtype of some type of the union, distribution laws over type constructors are absent, etc.). The typing of Typed Racket is internally defined in terms of propositional logic where atoms are the elements of a type environment (eg, x : τ ). The use of logical formulas coincides in CDuce to computing the types of capture variable of patterns (cf. the operator t p in Appendix E or in [START_REF] Frisch | Théorie, conception et réalisation d'un langage de programmation fonctionnel adapté à XML[END_REF]): the use of propositional logic corresponds to the use of Boolean connectives in CDuce's patterns and unsatisfiability of a formula to type emptiness. This is why all the examples in the "Challenges" section of [START_REF] Tobin-Hochstadt | Logical types for untyped languages[END_REF] can be easily defined and precisely typed in our system (straightforwardly with the syntactic sugar defined in the Appendix E of Part 1 [START_REF] Castagna | Polymorphic functions with set-theoretic types. Part 1: Syntax, semantics, and evaluation[END_REF]). Actually, these examples can already be defined and typed in monomorphic CDuce [START_REF] Benzaken | CDuce: an XML-friendly general purpose language[END_REF] since it already captures all the features characteristics of Typed Racket (recursive and union types, subtyping, occurrence typing, etc.) with the sole exception of polymorphism, a gap filled by this work. Typed Racket uses a limited form of local type inference: the application of a function to a polymorphic argument requires the application of an explicit type substitution to the argument. We do not have this limitation thanks to our tallying procedure that computes instantiations (type substitutitions) both for the function and for its argument. It is not clear whether using generic SMT solvers for typing (as suggested by [START_REF] Tobin-Hochstadt | Logical types for untyped languages[END_REF]) also in CDuce case (where subtyping is checked by type emptiness) would yield a better (sub)typing algorithm.

Local type inference was first formalized, as far as we know, by Pierce and Turner [START_REF] Pierce | Local type inference[END_REF]. They consider (i) a type system with type variables, arrow, top, and bottom types, (ii) an internal language with explicitly typed polymorphic functions that, to be applied, must be explicitly instantiated, and (iii) an external language in which some or all such instantiations can be omitted. Then they show how to infer type instantiations for programs of the external language in order to obtain, when possible, well-typed programs of the internal language. Our work shares much of the philosophy and goals of Pierce and Turner [START_REF] Pierce | Local type inference[END_REF]: expressions of grammar (3) form our external language, those of grammar [START_REF] Courcelle | Fundamental properties of infinite trees[END_REF] the internal one, and our sets of type-substitutions generalize Pierce and Turner's instantiations. Our work extends and generalizes Pierce and Turner's one in several ways. First, in an application we infer instantiation/typesubstitutions both for the function and for the argument, while [START_REF] Pierce | Local type inference[END_REF] does just the former (Typed Racket does the same). As a consequence while the application of the polymorphic identity λ α→α x.x to a function f of type (Int→Int)→Int can be typed in their systems (by inferring the instantiation { (Int→Int)→Int / α }) the application of the same f to the polymorphic identity cannot be typed (while our system types it by instantiating the argument by the substitution { Int / α }). Second, our system accounts for more expressive types, expressions, and subtyping relations. For instance, [START_REF] Pierce | Local type inference[END_REF] essentially solves the tallying problem for simple constraintsets whose form is the same as those obtained after applying our merge; instead we manipulate sets of constraint-sets (to account for alternatives generated to check either the typing of type-cases or the subtyping relation) and iterate the tallying problem with different cardinalities because of the presence of intersection types. Third, [START_REF] Pierce | Local type inference[END_REF] synthesizes an instantiation for a type variable only if its occurrences are either all positive or all negative and fails otherwise, while our system, thanks to the use of type connectives and recursive types, always generates a set of solvable equations.

Finally, we want to stress as a caveat that works on type reconstruction for intersection type systems are weakly related to our study. The reason is that the core of our technique consists in solving type (in-)equations by recursive types. With recursive types pure intersection type systems are trivially decidable since all terms can be typed by the type µX.X→X. The problem we tackle here, thus, is fundamentally different, namely, we check whether it is safe to apply to each other, expressions of two explicitly given (and possibly recursive) types in which some basic types may occur. There are however a few similarities with some techniques developed for pure intersection type systems that we briefly discuss next.

Coppo and Giannini [START_REF] Coppo | Principal types and unification for simple intersection type systems[END_REF] presented a decidable type checking algorithm for simple intersection type system where intersection is used in the left-hand side of an arrow and only a term variable is allowed to have different types in its different occurrences. They introduced labeled intersections and labeled intersection schemes, which are intended to represent potential intersections. During an application M N , the labeled intersection schemes of M and N would be unified to make them match successfully, yielding a transformation, a combination of substitutions and expansions. An expansion expands a labeled intersection into an explicit intersection. The intersection here acts like a variable binding similar to a quantifier in logic. Our rule (ALG-INST) is similar to the transformation. We instantiate a quantified type into several instances according to different situations (ie, the argument types), and then combine them as an intersection type. The difference is that we instantiate a parametric polymorphic function into a function with intersection types, while Coppo and Giannini transform a potential intersection into an explicit intersection. Besides, as the general intersection type system is not decidable [START_REF] Coppo | A new type assignment for λ-terms[END_REF], to get a decidable type checking algorithm, Coppo and Giannini used the intersection in a limited way, while we give some explicit type annotations for func-tions. Likewise, Jim [START_REF] Jim | A polar type system[END_REF] proposed a type inference algorithm for a polar type system where intersection is allowed only in negative positions and System F-like quantification only in positive ones.

Restricting intersection types to finite ranks (using Leivant's notion of rank [START_REF] Leivant | Polymorphic type inference[END_REF]) also yields decidable systems. Van Bakel [START_REF] Van Bakel | Intersection Type Disciplines in Lambda Calculus and Applicative Term Rewriting Systems[END_REF] gave the first unification-based inference algorithm for a rank 2 intersection type system. Jim [START_REF] Jim | What are principal typings and what are they good for?[END_REF] studied a decidable rank 2 intersection type system extended with recursion and parametric polymorphism. Kfoury and Wells proved decidability of type inference for intersection type systems of arbitrary finite rank [START_REF] Kfoury | Principality and decidable type inference for finite-rank intersection types[END_REF]. As a future work, we want to investigate decidability of rank-restricted versions of our calculus.

Conclusion

The work presented here, together with the one in [START_REF] Castagna | Polymorphic functions with set-theoretic types. Part 1: Syntax, semantics, and evaluation[END_REF], provides the theoretical bases and all the algorithmic tools needed to design and implement polymorphic languages for semi-structured data and, more generally, generic functional languages with recursive types and set-theoretic unions, intersections, and negations. In particular, our results made the polymorphic extension of CDuce [START_REF] Benzaken | CDuce: an XML-friendly general purpose language[END_REF] possible and pave the way to the definition of a real type system for XQuery 3.0 [START_REF] Robie | XQuery 3.0: An XML query language[END_REF] (not the current one in which all higher-order functions have type "function()"). Thanks to type reconstruction, these languages can have a syntax and semantics close to those of OCaml or Haskell, but also include primitives (in particular, complex patterns) that exploit the great expressive power of full-fledged settheoretic types. Symmetrically, as the red-black trees and max examples in Section 3.3 demonstrates, OCaml and Haskell would certainly benefit from the addition of set-theoretic type connectives: we plan to study such an extension in the near future.

Some problems are still open, notably the decidability of typesubstitution inference, but these are of theoretical nature and, as our experiments hitherto confirm, should not have any impact in practice. The only problem open in this second part of the work, that is the non determinism of the implicitly typed calculus, should have a negligible practical impact, insofar as it is theoretical (in practice, the semantics is deterministic but implementation dependent) and it concerns only the case when the type of (an instance of) a polymorphic function is tested at run-time: in our programming experience with CDuce we never met a single typecase for a function type. Nevertheless, it may be interesting to study how to remove such a latitude either by defining a canonical choice for the instances deduced by the inference system (a problem related to the existence of principal types), or by imposing reasonable restrictions, or by checking the flow of polymorphic functions by a static analysis.

On the practical side, by implementing the polymorphic extension of CDuce and applying it we realized that it would be useful to allow monomorphic type variables to occur in patterns (see Appendix A for examples) which in this work this would correspond to have a type case on types that may contain monomorphic type variables. How to do it is not straightforward and looks as a promising research direction. Other interesting practically-oriented directions of research are the study of heuristics to simplify types generated from constraints, so as to make type reconstruction for toplevel functions human friendly; the generation of meaningful type error messages; the study of efficient implementation of constraintsolving; the extension of the bridge between OCaml and CDuce to include polymorphic types and, later on, the inclusion of GADTs.

A. Examples of code

In this section we show examples of real code that follows the same pattern as the even function we defined in the introduction.

A.1 Red-Black trees

As a first example we show that the use of polymorphic set-theoretic types yields a better definition of Okasaki's implementation of red-black trees.

A red and black tree is a colored binary search tree in which all nodes are colored either black or red and that satisfies 4 invariants:

1. the root of the tree is black 2. the leaves of the tree are black 3. no red node has a red child 4. every path from the root to a leaf contains the same number of black nodes Thanks to our type system (and contrary to Okasaki's version) the implementation below ensures by typing that the operations on red-black trees (notably, the insertion) satisfy the first three invariants, as well as, that the ins_aux function, local to insertion, never returns empty trees (yet another important property that, in ML/Haskell Okasaki's version, types cannot ensure). We invite the reader to refer to the excellent Okasaki's monograph [START_REF] Okasaki | Purely Functional Data Structures[END_REF] for details about Okasaki's algorithm -that our code faithfully follows-and the documentation of the language CDuce for details about the syntax we used, which is standard CDuce syntax apart from the presence of type variables. 8 Let us instead spend some words to comment the types, since they are the real novelty and the added value of our definition. First, notice that we used the full palette of our types: unions, intersections, negations (difference), and type variables. Red-black trees (Btrees) are black-rooted RBtrees (invariant 1), which 8 For the reader convenience we recall that in CDuce XML types/pattern/expressions may have the form where the list of arrow types that follow the function name form the intersection type (ie, the interface) of the function.

<tag
are themselves black-rooted trees or red-rooted trees. The difference between the last two is that the latter cannot be leaves (invariant 2) and their children can only be black-rooted trees (invariant 3).

The insert function takes an element x of type α, and returns a function that maps red-black trees into red-black trees.

insert :: α -> Btree(α) -> Btree(α) By examining the code of insert it is easy to see that if the argument tree is empty a red-rooted tree is returned, otherwise the element is inserted in the appropriate subtree and the whole tree is then balanced by the function balance. This function has the following type (which follows the same typing pattern as the function even defined in the introduction): balance :: ( Unbalanced(α)->Rtree(α) ) & ( β\Unbalanced(α)->β\Unbalanced(α) ) This type states that balance transforms an unbalanced tree into a (balanced) red-rooted tree and leaves all other trees (in particular the balanced ones) unchanged. The core of our definition is the type of ins_aux:

ins_aux :: ( [] -> Rtree(α) ) & ( Btree(α)\[] -> RBtree(α)\[] )
& ( Rtree(α) -> Rtree(α)|Wrongtree(α) ) which precisely describes the behaviour of the function. Notice that the domain of ins_aux (which is the union of the three domains of the arrows forming its intersection type) is exactly RBtree(α). The intersection type describes the behaviour of ins_aux for each form of an RBtree -ie, empty, black-rooted, and red-rooted-. The type system needs the full precision of this type to infer whether the calls to balance in the body of ins_aux are applied to a balanced or an unbalanced tree: even a slight approximation of this type, such as

ins_aux :: ( Btree(α)\[] -> RBtree(α)\[] )
& ( Rtree(α)|[] -> Rtree(α)|Wrongtree(α) ) makes type-checking fail. By examining the type of ins_aux it is easy to see that ins_aux always returns either a (balanced) black-rooted tree or a tree with a red root in which one of the children may be a Rtree. In case of a tree with a red root, a (balanced) red-black tree is then obtained by changing the color of the root to black, as it is done in the last line of insert.

The implementation above must be compared with the corresponding version in monomorphic CDuce: Wrongleft and Wrongright) in order to describe the polymorphic behavior of balance -whose type results, thus, much more obscure-. Our implementation must also be compared with the version given by Rowan Davies in his PhD Thesis [START_REF] Davies | Practical Refiniment-Type Checking[END_REF] which uses polymorphic intersection types and type inference. Contrary to our definition, Davies's implementation (i) does not statically verify invariant 1, (ii) it introduces -as our monomorphic version does-several intermediate type definitions to specify the behavior of local functions, and (iii) it does not faithfully reproduce Okasaki implementation since it needs the definition of several auxiliary functions absent from Okasaki's (and our) formulation.

type
[] -> [] ; Wrongleft -> Wrongleft ; Wrongright -> Wrongright) | <black (z)>[ <red (y)>[ <red (x)>[ a b ] c ] d ] | <black (z)>[ <red (x)>[ a <red (y)>[ b c ] ] d ] | <black (x)>[ a <red (z)>[ <red (y)>[ b c ] d ] ] | <black (x)>[ a <red (y)>[ b <red (z)>[ c d ] ] ] -> <red (y)>[ <black (x)>[ a b ] <black (z)>[ c d ] ] | x -> x let insert (x : Int) (t : Btree) : Btree = let ins_aux ( [] -> Rtree ; Btree\[] -> RBtree\[]; Rtree -> Rtree|Wrongtree) | [] -> <red elem=x>[ [] [] ] | (<(color) elem=y>[ a b ]) & z -> if x <<
Likewise, there exist other implementations that are able to ensure/verify the first invariants of redblack trees (eg, by using GADTs or finite tree automata) but they all need extra definitions of intermediate functions or operations: as far as we know ours types are the only system that can statically ensure the invariants above simply by decorating (with types) the original Okasaki's code without any further modification.

Notice that the definition of balance given above and the one in Section 3.3 differ for a couple of details. First, the name of the types require mandatory type parameters when their definitions contain free type variable (eg, we have to write RBtree(α) rather than just RBtree): this is the behavior implemented in the current development version of CDuce, and we omitted this detail in the code of Section 3.3 just for space reasons. More importantly, the union pattern of the first branch of the pattern matching is intersected with the type Unbalanced(α). The reason is that this type is strictly contained in the type accepted by the union pattern and, thereforere, this branch can be selected for values that are not in Unbalanced(α) (notice that balance can be applied to any value). Now for these values the interfaces of balance declares that a result of the same type is returned, which is not true since the first rather than the second branch is selected (and the latter transforms a black-rooted tree into a red-rooted one). This is why without the intersection in the pattern the type-checker rejects the definition by pointing out the problem. By adding the intersection we force the first branch to be selected only for values of type Unbalanced(α), and the function type-checks.

There is still a last glitch, at least to run the example on the current development version of CDuce. Notice that we used Unbalanced(α) in the pattern and that this type contains the monomorphic variable α. The current develoment version of CDuce does not allow monomorphic variables to occur in patterns, yet (this is listed as future work in Section 7). In order to execute balance on the current development version of CDuce there are (at least) three solutions, which are all as valid as the one presented before. The first solution is to restrict the domain of balance to Unbalanced(α) | RBtree(α). This can be done by declaring for balance the interface ( Unbalanced(α) -> Rtree(α) ; β & RBtree(α) -> β & RBtree(α) ) (notice that the intersection of Unbalanced(α) and RBtree(α) is empty so the difference in the interface and the intersection in the pattern are no longer necessary). The second solution is to use as intersection in the pattern the type Unbalanced(Any) to overapproximate Unbalanced(α). This however requires to modify the interface of balance accordingly into ( Unbalanced(α) -> Rtree(α) ; β\Unbalanced(Any) -> β\Unbalanced(Any) ) to capture the precise cases in which the second branch is selected. The third, more verbose, solution is to get rid again of the intersection pattern by declaring in the interface that the second arrow type applies only to values that are not in the accepted type of the first union pattern, that is, ( Unbalanced(α) -> Rtree(α) ; β\UTree -> β\UTree), where UTree is the accepted type of the first union pattern, which is obtained by replacing in the pattern Any for every capture variable occurring in it, namely: A.2 Soap envelopes As a second usage example of the typing pattern followed by even we explore a typical XML application to process envelopes. Soap envelopes are a standardized format to communicate information wrapped in XML. An envelope contains a body and an optional header as described by the following type definitions. When applied to a function f, enrich returns a function that adds to the header of an envelope the result obtained by applying f to the body of the envelope, and recursively applies this transformation inside the body and in possible subtrees. Once more, in the definition of enrich we used pattern with monomorphic variables, therefore the same considerations as for the red-black tree example apply, too. The function enrich can then be typically used as in

xtransform anXMLdoc with | x & T -> enrich f_T x | x & <Envelope>_ -> enrich f x
where f_T is specific for type T and f is generic. The expression above transforms all the envelopes in the anXMLdoc document by preserving the type of all its subcomponents with the addition of the information on the headers, when it is missing. Again this must be contrasted with the monomorphic version which must list all possible alternatives for the input type and in which the types of the contents of the envelope and the header are not preserved since they are subsumed to

B. Implicitly-Typed Calculus

We want sets of type-substitutions to be inferred by the system, not written by the programmer. To this end, we define a calculus without type substitutions (called implicitly-typed, in contrast to the calculus in [START_REF] Courcelle | Fundamental properties of infinite trees[END_REF] in Section 2, which we henceforth call explicitly-typed), for which we define a type-substitutions inference system. As explained in Section 3, we do not try to infer decorations in λ-abstractions, and we therefore look for completeness of the type-substitutions inference system with respect to the expressions written according to the following grammar: We write E0 for the set of such expressions. The implicitly-typed calculus defined in this section corresponds to the type-substitution erasures of the expressions of E0. These are the terms generated by the grammar above without using the last production, that is, without the application of sets of type-substitutions. We then define the type-substitutions inference system by determining where the rule (ALG-INST) have to be used in the typing derivations of explicitly-typed expressions. Finally, we propose an incomplete but more tractable restriction of the type-substitutions inference system, which, we believe, is powerful enough to be used in practice.

B.1 Implicitly-typed Calculus Definition B.1. An implicitly-typed expression a is an expression without any type substitutions. It is inductively generated by the following grammar:

a ::= c | x | (a, a) | πi(a) | a a | λ ∧ i∈I t i →s i x.a | a∈t ? a : a
where ti, si range over types and t ∈ T0 is a ground type. We write EA to denote the set of all implicitlytyped expressions.

Clearly, EA is a proper subset of E0. The erasure of explicitly-typed expressions to implicitly-typed expressions is defined as follows:

Definition B.2. The erasure is the mapping from E0 to EA defined as erase(c) = c erase(x) = x erase((e1, e2)) = (erase(e1), erase(e2)) erase(πi(e)) = πi(erase(e)) erase(λ ∧ i∈I t i →s i x.e) = λ ∧ i∈I t i →s i x.erase(e) erase(e1e2) = erase(e1)erase(e2) erase(e∈t ? e1 : e2) = erase(e)∈t ? erase(e1) : erase(e2) erase(e[σj]j∈J ) = erase(e)

Prior to introducing the type inference rules, we define a preorder on types, which is similar to the type variable instantiation in ML but with respect to a set of type substitutions. Definition B.3. Let s and t be two types and ∆ a set of type variables. We define the following relations:

[σi]i∈I s ⊑∆ t def ⇐⇒ i∈I sσi ≤ t and ∀i∈I. σi ♯ ∆ s ⊑∆ t def ⇐⇒ ∃[σi]i∈I such that [σi]i∈I s ⊑∆ t
We write s ⊑∆ t if it does not exist a set of type substitutions [σi]i∈I such that [σi]i∈I s ⊑∆ t. We now prove some properties of the preorder ⊑∆.

Lemma B.4. Let t1 and t2 be two types and ∆ a set of type variables. If t1 ⊑∆ s1 and t2 ⊑∆ s2, then (t1 ∧ t2) ⊑∆ (s1 ∧ s2) and (t1 × t2) ⊑∆ (s1 × s2).

Proof. Let [σi 1 ]i 1 ∈I 1 t1 ⊑∆ s1 and [σi 2 ]i 2 ∈I 2 t2 ⊑∆ s2. Then i∈I 1 ∪I 2 (t1 ∧ t2)σi ≃ ( i∈I 1 ∪I 2 t1σi) ∧ ( i∈I 1 ∪I 2 t2σi) ≤ ( i 1 ∈I 1 t1σi 1 ) ∧ ( i 2 ∈I 2 t2σi 2 ) ≤ s1 ∧ s2 and i∈I 1 ∪I 2 (t1 × t2)σi ≃ (( i∈I 1 ∪I 2 t1σi) × ( i∈I 1 ∪I 2 t2σi)) ≤ (( i 1 ∈I 1 t1σi 1 ) × ( i 2 ∈I 2 t2σi 2 )) ≤ (s1 × s2) Lemma B.
,i 2 ]i 1 ∈I 1 ,i 2 ∈I 2 such that σi 1 ,i 2 (α) =      σi 1 (α) if α ∈ (var(t1) \ ∆) σi 2 (α) if α ∈ (var(t2) \ ∆) α otherwise So we have i 1 ∈I 1 ,i 2 ∈I 2 (t1 ∨ t2)σi 1 ,i 2 ≃ i 1 ∈I 1 ( i 2 ∈I 2 (t1 ∨ t2)σi 1 ,i 2 ) ≃ i 1 ∈I 1 ( i 2 ∈I 2 ((t1σi 1 ,i 2 ) ∨ (t2σi 1 ,i 2 ))) ≃ i 1 ∈I 1 ( i 2 ∈I 2 (t1σi 1 ∨ t2σi 2 )) ≃ i 1 ∈I 1 (t1σi 1 ∨ ( i 2 ∈I 2 t2σi 2 )) ≃ ( i 1 ∈I 1 t1σi 1 ) ∨ ( i 2 ∈I 2 t2σi 2 ) ≤ s1 ∨ s2
Notice that two successive instantiations can be safely merged into one (see Lemma B.6). Henceforth, we assume that there are no successive instantiations in a given derivation tree. In order to guess where to insert sets of type-substitutions in an implicitly-typed expression, we consider each typing rule of the explicitly-typed calculus used in conjunction with the instantiation rule (ALG-INST). If instantiation can be moved through a given typing rule without affecting typability or changing the result type, then it is not necessary to infer type substitutions at the level of this rule. First of all, consider a typing derivation ending with (ALG-PAIR) where both of its sub-derivations end with (ALG-INST) 9 :

Lemma B.6. Let e be an explicitly-typed expression and

. . .

∆ ; Γ ⊢ A e1 : t1 ∀j1 ∈ J1. σj 1 ♯ ∆ ∆ ; Γ ⊢ A e1[σj 1 ]j 1 ∈J 1 : j 1 ∈J 1 t1σj 1 . . . ∆ ; Γ ⊢ A e2 : t2 ∀j2 ∈ J2. σj 2 ♯ ∆ ∆ ; Γ ⊢ A e2[σj 2 ]j 2 ∈J 2 : j 2 ∈J 2 t1σj 2 ∆ ; Γ ⊢ A (e1[σj 1 ]j 1 ∈J 1 , e2[σj 2 ]j 2 ∈J 2 ) : ( j 1 ∈J 1 t1σj 1 ) × ( j 2 ∈J 2 t1σj 2 )
We rewrite such a derivation as follows:

. . .

∆ ; Γ ⊢ A e1 : t1 . . . ∆ ; Γ ⊢ A e2 : t2 ∆ ; Γ ⊢ A (e1, e2) : t1 × t2 ∀j ∈ J1 ∪ J2. σj ♯ ∆ ∆ ; Γ ⊢ A (e1, e2)[σj]j∈J 1 ∪J 2 : j∈J 1 ∪J 2 (t1 × t2)σj Clearly, j∈J 1 ∪J 2 (t1 × t2)σj ≤ ( j 1 ∈J 1 t1σj 1 ) × ( j 2 ∈J 2 t1σj 2 ).
Then by subsumption we can deduce that (e1, e2)[σj]j∈J 1 ∪J 2 also has the type ( j 1 ∈J 1 t1σj 1 ) × ( j 2 ∈J 2 t1σj 2 ). Therefore, we can disregard the sets of type substitutions that are applied inside a pair, since inferring them outside the pair is equivalent. Hence, we can use the following inference rule for pairs. ∆ ; Γ ⊢ I a1 : t1 ∆ ; Γ ⊢ I a2 : t2 ∆ ; Γ ⊢ I (a1, a2) : t1 × t2 Next, consider a derivation ending of (ALG-PROJ) whose premise is derived by (ALG-INST):

. . .

∆ ; Γ ⊢ A e : t ∀j ∈ J. σj ♯ ∆ ∆ ; Γ ⊢ A e[σj]j∈J : j∈J tσj ( j∈J tσj) ≤ 1 × 1 ∆ ; Γ ⊢ A πi(e[
σj]j∈J ) : π π πi( j∈J tσj) According to Lemma C.8 in the companion paper [START_REF] Castagna | Polymorphic functions with set-theoretic types. Part 1: Syntax, semantics, and evaluation[END_REF], we have π π πi( j∈J tσj) ≤ j∈J π π πi(t)σj, but the converse does not necessarily hold. For example, π π π1(((t1

× t2) ∨ (s1 × α \ s2)){ s 2/ α }) = t1{ s 2/ α } while (π π π1((t1 × t2) ∨ (s1 × α \ s2))){ s 2/ α } = (t1 ∨ s1){ s 2/
α }. So we cannot exchange the instantiation and projection rules without losing completeness. However, as ( j∈J tσj) ≤ 1 × 1 and ∀j ∈ J. σj ♯ ∆, we have t ⊑∆ 1 × 1. This indicates that for an implicitly-typed expression πi(a), if the inferred type for a is t and there exists [σj]j∈J such that [σj]j∈J t ⊑∆ 1 × 1, then we infer the type π π πi( j∈J tσj) for πi(a). Let ∐ i ∆ (t) denote the set of such result types, that is,

∐ i ∆ (t) = {u | [σj]j∈J t ⊑∆ 1 × 1, u = π π πi( j∈J tσj)}
Formally, we have the following inference rule for projections ∆ ; Γ ⊢ I a : t u ∈ ∐ i ∆ (t) ∆ ; Γ ⊢ I πi(a) : u The following lemma tells us that ∐ i ∆ (t) is "morally" closed by intersection, in the sense that if we take two solutions in ∐ i ∆ (t), then we can take also their intersection as a solution, since there always exists in ∐ i ∆ (t) a solution at least as precise as their intersection.

Lemma B.7. Let t be a type and ∆ a set of type variables. If u1

∈ ∐ i ∆ (t) and u2 ∈ ∐ i ∆ (t), then ∃u0 ∈ ∐ i ∆ (t). u0 ≤ u1 ∧ u2. Proof. Let [σj k ]j k ∈J k t ⊑∆ 1 × 1 and u k = π π πi( j k ∈J k tσj k ) for k = 1, 2. Then [σj]j∈J 1 ∪J 2 t ⊑∆ 1 × 1. So π π πi( j∈J 1 ∪J 2 tσj) ∈ ∐ i ∆ (t)
. Moreover, by Lemma C.6 in the companion paper [START_REF] Castagna | Polymorphic functions with set-theoretic types. Part 1: Syntax, semantics, and evaluation[END_REF], we have π π πi(

j∈J 1 ∪J 2 tσj) ≤ π π πi( j 1 ∈J 1 tσj 1 ) ∧ π π πi( j 2 ∈J 2 tσj 2 ) = u1 ∧ u2
Since we only consider λ-abstractions with empty decorations, we can consider the following simplified version of (ALG-ABSTR) that does not use relabeling

∀i ∈ I. ∆ ∪ var( i∈I (ti → si)) ; Γ, x : ti ⊢ A e : s ′ i and s ′ i ≤ si ∆ ; Γ ⊢ A λ ∧ i∈I t i →s i x.e : i∈I (ti → si) (ALG-ABSTR0)
Suppose the last rule used in the sub-derivations is (ALG-INST).

∀i ∈ I.

     . . . ∆ ′ ; Γ, x : ti ⊢ A e : s ′ i ∀j ∈ J. σj ♯ ∆ ′ ∆ ′ ; Γ, x : ti ⊢ A e[σj]j∈J : j∈J s ′ i σj j∈J s ′ i σj ≤ si ∆ ′ = ∆ ∪ var( i∈I (ti → si)) ∆ ; Γ ⊢ A λ ∧ i∈I t i →s i x.e[σj]j∈J : i∈I (ti → si)
From the side conditions, we deduce that s ′ i ⊑ ∆ ′ si for all i ∈ I. Instantiation may be necessary to bridge the gap between the computed type s ′ i for e and the type si required by the interface, so inferring type substitutions at this stage is mandatory. Therefore, we propose the following inference rule for abstractions.

∀i ∈ I. ∆ ∪ var( i∈I ti → si) ; Γ, (x : ti) ⊢ I a : s ′ i s ′ i ⊑ ∆∪var( i∈I t i →s i ) si ∆ ; Γ ⊢ I λ ∧ i∈I t i →s i x.a : i∈I ti → si
In the application case, suppose both sub-derivations end with (ALG-INST):

. . .

∆ ; Γ ⊢ A e1 : t ∀j1 ∈ J1. σj 1 ♯ ∆ ∆ ; Γ ⊢ A e1[σj 1 ]j 1 ∈J 1 : j 1 ∈J 1 tσj 1 . . . ∆ ; Γ ⊢ A e2 : s ∀j2 ∈ J2. σj 2 ♯ ∆ ∆ ; Γ ⊢ A e2[σj 2 ]j 2 ∈J 2 : j 2 ∈J 2 sσj 2 j 1 ∈J 1 tσj 1 ≤ 0 → 1 j 2 ∈J 2 sσj 2 ≤ dom( j 1 ∈J 1 tσj 1 ) ∆ ; Γ ⊢ A (e1[σj 1 ]j 1 ∈J 1 )(e2[σj 2 ]j 2 ∈J 2 ) : ( j 1 ∈J 1 tσj 1 ) • ( j 2 ∈J 2 sσj 2 )
Instantiation may be needed to bridge the gap between the (domain of the) function type and its argument (e.g., to apply λ α→α x.x to 42). The side conditions imply that [σj 1 ]j 1 ∈J 1 t ⊑∆ 0 → 1 and [σj 2 ]j 2 ∈J 2 s ⊑∆ dom( j 1 ∈J 1 tσj 1 ). Therefore, given an implicitly-typed application a1a2 where a1 and a2 are typed with t and s respectively, we have to find two sets of substitutions [σj 1 ]j 1 ∈J 1 and [σj 2 ]j 2 ∈J 2 verifying the above preorder relations to be able to type the application. If such sets of substitutions exist, then we can type the application with ( j 1 ∈J 1 tσj 1 ) • ( j 2 ∈J 2 sσj 2 ). Let t •∆ s denote the set of such result types, that is,

t •∆ s def =    u [σi]i∈I t ⊑∆ 0→1 [σj]j∈J s ⊑∆ dom( i∈I tσi) u = i∈I tσi • j∈J sσj    This set
∈ t •∆ s, then ∃u0 ∈ t •∆ s. u0 ≤ u1 ∧ u2. Proof. Let u k = ( i k ∈I k tσi k ) • ( j k ∈J k sσj k ) for k = 1, 2.
According to Lemma C.18 in the companion paper [START_REF] Castagna | Polymorphic functions with set-theoretic types. Part 1: Syntax, semantics, and evaluation[END_REF], we have

( i∈I 1 ∪I 2 tσi) • ( j∈J 1 ∪J 2 sσj) ∈ t •∆ s and ( i∈I 1 ∪I 2 tσi) • ( j∈J 1 ∪J 2 sσj) ≤ k=1,2 ( i k ∈I k tσi k ) • ( j k ∈J k sσj k ) = u1 ∧ u2.
For type cases, we distinguish the four possible behaviours: (i) no branch is selected, (ii) the first branch is selected, (iii) the second branch is selected, and (iv) both branches are selected. In all these cases, we assume that the premises end with (ALG-INST). In case (i), we have the following derivation:

. . . ∆ ; Γ ⊢ A e : t ′ ∀j ∈ J. σj ♯ ∆ ∆ ; Γ ⊢ A e[σj]j∈J : j∈J t ′ σj j∈J t ′ σj ≤ 0 ∆ ; Γ ⊢ A (e[σj]j∈J )∈t ? e1 : e2 : 0 Clearly, the side conditions implies t ′ ⊑∆ 0. The type inference rule for implicitly-typed expressions corresponding to this case is then ∆ ; Γ ⊢ I a : t ′ t ′ ⊑∆ 0 ∆ ; Γ ⊢ I (a∈t ? a1 : a2) : 0 For case (ii), consider the following derivation:

. . .

∆ ; Γ ⊢ A e : t ′ σj ♯ ∆ ∆ ; Γ ⊢ A e[σj]j∈J : j∈J t ′ σj j∈J t ′ σj ≤ t . . . ∆ ; Γ ⊢ A e1 : s1 σj 1 ♯ ∆ ∆ ; Γ ⊢ A e1[σj 1 ]j 1 ∈J 1 : j 1 ∈J 1 s1σj 1 ∆ ; Γ ⊢ A (e[σj]j∈J )∈t ? (e1[σj 1 ]j 1 ∈J 1 ) : e2 : j 1 ∈J 1 s1σj 1
First, such a derivation can be rewritten as . . .

∆ ; Γ ⊢ A e : t ′ σj ♯ ∆ ∆ ; Γ ⊢ A e[σj]j∈J : j∈J t ′ σj j∈J t ′ σj ≤ t . . . ∆ ; Γ ⊢ A e1 : s1 ∆ ; Γ ⊢ A (e[σj]j∈J )∈t ? e1 : e2 : s1 σj 1 ♯ ∆ ∆ ; Γ ⊢ A ((e[σj]j∈J )∈t ? e1 : e2)[σj 1 ]j 1 ∈J 1 ) : j 1 ∈J 1 s1σj 1
This indicates that it is equivalent to apply the substitutions [σj 1 ]j 1 ∈J 1 to e1 or to the whole type case expression. Looking at the derivation for e, for the first branch to be selected we must have t ′ ⊑∆ t. Note that if t ′ ⊑∆ ¬t, we would have t ′ ⊑∆ 0 by Lemma B.4, and no branch would be selected. Consequently, the type inference rule for a type case where the first branch is selected is as follows.

∆ ; Γ ⊢ I a : t ′ t ′ ⊑∆ t t ′ ⊑∆ ¬t ∆ ; Γ ⊢ I a1 : s ∆ ; Γ ⊢ I (a∈t ? a1 : a2) : s Case (iii) is similar to case (ii) where t is replaced by ¬t.

At last, consider a derivation of Case (iv):

                               . . . ∆ ; Γ ⊢ A e : t ′ ∀j ∈ J. σj ♯ ∆ ∆ ; Γ ⊢ A e[σj]j∈J : j∈J t ′ σj j∈J t ′ σj ≤ ¬t and . . . ∆ ; Γ ⊢ A e1 : s1 ∀j1 ∈ J1. σj 1 ♯ ∆ ∆ ; Γ ⊢ A e1[σj 1 ]j 1 ∈J 1 : j 1 ∈J 1 s1σj 1 j∈J t ′ σj ≤ t and . . . ∆ ; Γ ⊢ A e2 : s2 ∀j2 ∈ J2. σj 2 ♯ ∆ ∆ ; Γ ⊢ A e2[σj 2 ]j 2 ∈J 2 : j 2 ∈J 2 s2σj 2 ∆ ; Γ ⊢ A (e[σj]j∈J ∈t ? (e1[σj 1 ]j 1 ∈J 1 ) : (e2[σj 2 ]j 2 ∈J 2 )) : j 1 ∈J 1 s1σj 1 ∨ j 2 ∈J 2 s2σj
2 Using α-conversion if necessary, we can assume that the polymorphic type variables of e1 and e2 are distinct, and therefore we have (var(s1) \ ∆) ∩ (var(s2) \ ∆) = ∅. According to Lemma B.5, we get

s1 ∨s2 ⊑∆ j 1 ∈J 1 s1σj 1 ∨ j 2 ∈J 2 s2σj 2 . Let [σj 12 ]j 12 ∈J 12 s1 ∨s2 ⊑∆ j 1 ∈J 1 s1σj 1 ∨ j 2 ∈J 2 s2σj 2 .
We can rewrite this derivation as We now consider the part of the derivation tree which concerns e. With the specific set of substitutions [σj]j∈J , we have j∈J t ′ σj ≤ ¬t and j∈J t ′ σj ≤ t, but it does not mean that we have t ′ ⊑∆ t and t ′ ⊑∆ ¬t in general. If t ′ ⊑∆ t and/or t ′ ⊑∆ ¬t hold, then we are in one of the previous cases (i) -(iii) (i.e., we type-check at most one branch), and the inferred result type for the whole type case belongs to 0, s1 or s2. We can then use subsumption to type the whole type-case expression with s1 ∨ s2. Otherwise, both branches are type-checked, and we deduce the corresponding inference rule as follows.

                     . . . ∆ ; Γ ⊢ A e : t ′ ∀j ∈ J. σj ♯ ∆ ∆ ; Γ ⊢ A e[
∆ ; Γ ⊢ I a : t ′ t ′ ⊑∆ ¬t and ∆ ; Γ ⊢ I a1 : s1 t ′ ⊑∆ t and ∆ ; Γ ⊢ I a2 : s2 ∆ ; Γ ⊢ I (a∈t ? a1 : a2) : s1 ∨ s2 From the study above, we deduce the type-substitution inference rules for implicitly-typed expressions given in Figure 5, which are the same as those in Section 3 except for the rules for products.

∆ ; Γ ⊢ I c : bc (INF-CONST) ∆ ; Γ ⊢ I x : Γ(x) (INF-VAR) ∆ ; Γ ⊢ I a1 : t1 ∆ ; Γ ⊢ I a2 : t2 ∆ ; Γ ⊢ I (a1, a2) : t1 × t2 (INF-PAIR) ∆ ; Γ ⊢ I a : t u ∈ ∐ i ∆ (t) ∆ ; Γ ⊢ I πi(a) : u (INF-PROJ) ∆ ; Γ ⊢ I a1 : t ∆ ; Γ ⊢ I a2 : s u ∈ t •∆ s ∆ ; Γ ⊢ I a1a2 : u (INF-APPL) ∀i ∈ I.    ∆ ∪ var( i∈I ti → si) ; Γ, (x : ti) ⊢ I a : s ′ i s ′ i ⊑ ∆∪var( i∈I t i →s i ) si ∆ ; Γ ⊢ I λ ∧ i∈I t i →s i x.a : i∈I ti → si (INF-ABSTR) ∆ ; Γ ⊢ I a : t ′ t ′ ⊑∆ 0 ∆ ; Γ ⊢ I (a∈t ? a1 : a2) : 0 (INF-CASE-NONE) ∆ ; Γ ⊢ I a : t ′ t ′ ⊑∆

B.2 Soundness and Completeness

We now prove that the inference rules of the implicitly-typed calculus given in Figure 5 are sound and complete with respect to the type system of the explicitly-typed calculus (i.e., Figure 1 extended with the standard rules for products).

To construct an explicitly-typed expression from an implicitly-typed one a, we have to insert sets of substitutions in a each time a preorder check is performed in the rules of Figure 5. For an abstraction λ ∧ i∈I t i →s i x.a, different sets of substitutions may be constructed when type checking the body under the different hypotheses x : ti. For example, let a = λ (Int→Int)∧(Bool→Bool) x.(λ α→α y.y)x. When a is type-checked against Int → Int, that is, x is assumed to have type Int, we infer the type substitution { Int / α } for (λ α→α y.y). Similarly, we infer { Bool / α } for (λ α→α y.y), when a is type-checked against Bool → Bool. We have to collect these two different substitutions when constructing the explicitlytyped expression e which corresponds to a. To this end, we introduce an intersection operator e ⊓ e ′ of expressions which is defined only for pair of expressions that have similar structure but different type substitutions. For example, the intersection of (λ α→α y.y)[{ Int / α }]x and (λ α→α y.y)[{ Bool / α }]x will be (λ α→α y.y)[{ Int / α }, { Bool / α }]x. Definition B.9. Let e, e ′ ∈ E0 be two expressions. Their intersection e ⊓ e ′ is defined by induction as:

c ⊓ c = c x ⊓ x = x (e1, e2) ⊓ (e ′ 1 , e ′ 2 ) = ((e1 ⊓ e ′ 1 ), (e2 ⊓ e ′ 2 )) πi(e) ⊓ πi(e ′ ) = πi(e ⊓ e ′ ) e1e2 ⊓ e ′ 1 e ′ 2 = (e1 ⊓ e ′ 1 )(e2 ⊓ e ′ 2 ) (λ ∧ i∈I t i →s i x.e) ⊓ (λ ∧ i∈I t i →s i x.e ′ ) = λ ∧ i∈I t i →s i x.(e ⊓ e ′ ) (e0∈t ? e1 : e2) ⊓ (e ′ 0 ∈t ? e ′ 1 : e ′ 2 ) = e0 ⊓ e ′ 0 ∈t ? e1 ⊓ e ′ 1 : e2 ⊓ e ′ 2 (e1[σj]j∈J ) ⊓ (e ′ 1 [σj] j∈J ′ ) = (e1 ⊓ e ′ 1 )[σj] j∈J∪J ′ e ⊓ (e ′ 1 [σj] j∈J ′ ) = (e[σ id ]) ⊓ (e ′ 1 [σj] j∈J ′ ) if e = e1[σj]j∈J (e1[σj]j∈J ) ⊓ e ′ = (e1[σj]j∈J ) ⊓ (e ′ [σ id ]) if e ′ = e ′ 1
[σj] j∈J ′ where σ id is the identity type substitution and is undefined otherwise.

The intersection of the same constant or the same variable is the constant or the variable itself. If e and e ′ have the same form, then their intersection is defined if the intersections of their corresponding sub-expressions are defined. In particular when e is of the form e1 [σj] ). In order not to lose any inferred information and be able to reuse the cases defined above, we add the identity substitution σ id to the expression without substitutions (i.e., e[σ id ] or e ′ [σ id ]). Let us infer the substitutions for the abstraction λ (t 1 →s 1 )∧(t 2 →s 2 ) x.e. Assume that we have inferred some substitutions for the body e under t1 → s1 and t2 → s2 respectively, yielding two explicitlytyped expressions e1 and e2[σj]j∈J . If we did not add the identity substitution σ id for the intersection of e1 and e2[σj]j∈J , that is, e1 ⊓ (e2[σj]j∈J ) were (e1 ⊓ e2)[σj]j∈J rather than (e1 ⊓ e2)([σ id ] ∪ [σj]j∈J ), then the substitutions we inferred under t1 → s1 would be lost since they may be modified by [σj]j∈J .

⊓ e ′ i ) = erase(ei) = erase(e ′ i ). Therefore e1e2 ⊓ e ′ 1 e ′ 2 exists and erase((e1e2) ⊓ (e ′ 1 e ′ 2 )) = erase((e1 ⊓ e ′ 1 )(e2 ⊓ e ′ 2 )) = erase(e1 ⊓ e ′ 1 )erase(e2 ⊓ e ′ 2 ) = erase(e1)erase(e2) = erase(e1e2)
Similarly, we also have erase((e1e2) ⊓ (e ′ 1 e ′ 2 )) = erase(e ′ 1 e ′ 2 ). λ ∧ i∈I t i →s i x.e, λ ∧ i∈I t i →s i x.e ′ : we have erase(e) = erase(e ′ ). By induction, e ⊓ e ′ exists and erase(e ⊓ e ′ ) = erase(e) = erase(e ′ ). Therefore (λ ∧ i∈I t i →s i x.e) ⊓ (λ ∧ i∈I t i →s i x.e ′ ) exists and erase((λ ∧ i∈I t i →s i x.e) ⊓ (λ ∧ i∈I t i →s i x.e ′ )) = erase(λ ∧ i∈I t i →s i x.(e ⊓ e ′ )) = λ ∧ i∈I t i →s i x.erase((e ⊓ e ′ )) = λ ∧ i∈I t i →s i x.erase(e) = erase(λ ∧ i∈I t i →s i x.e)

Similarly, we also have erase((λ ∧ i∈I t i →s i x.e) ⊓ (λ ∧ i∈I t i →s i x.e ′ )) = erase(λ ∧ i∈I t i →s i x.e ′ ) e0∈t ? e1 : e2, e Proof. According to Lemma B.10, e ⊓ e ′ exists and erase(e ⊓ e ′ ) = erase(e) = erase(e ′ ). We only prove ∆ ; Γ ⊢ e ⊓ e ′ : t as the other case is similar. For simplicity, we just consider one set of type substitutions. For several sets of type substitutions, we can either compose them or apply (instinter) several times. The proof proceeds by induction on ∆ ; Γ ⊢ e : t. . . .

∆ ; Γ ⊢ e1 : t1 . . . ∆ ; Γ ⊢ e2 : t2 ∆ ; Γ ⊢ (e1, e2) : t1 × t2 (pair)
As erase(e ′ ) = (erase(e1), erase(e2)), e ′ is either (e

∆ ′′ = ∆ ∪ var( i∈I ti → si) ∆ ; Γ ⊢ λ ∧ i∈I t i →s i x.e0 : i∈I ti → si (abstr)
As erase(e ′ ) = λ ∧ i∈I t i →s i x.erase(e0), e ′ is either λ ∧ i∈I t i →s i x.e ′ 0 or (λ ∧ i∈I t i →s i x.e ′ 0 )[σj]j∈J such that erase(e ′ 0 ) = erase(e0). As λ ∧ i∈I t i →s i x.e ′ 0 is well-typed under ∆ ′ and Γ ′ , e ′ 0 ♯ ∆ ′ ∪ var( i∈I ti → si). By induction, we have ∆ ′′ ; Γ, (x : ti) ⊢ e0 ⊓ e ′ 0 : si. Then by (abstr), we have ∆ ; Γ ⊢ λ ∧ i∈I t i →s i x.e0 ⊓ e ′ 0 : i∈I ti → si. If e ′ = λ ∧ i∈I t i →s i x.e ′ 0 , then e ⊓ e ′ = λ ∧ i∈I t i →s i x.e0 ⊓ e ′ 0 . So the result follows. Otherwise, e ⊓ e ′ = (λ ∧ i∈I t i →s i x.e0 ⊓ e ′ 0 )[σ id , σj]j∈J . Since e ′ ♯ ∆, we have σj ♯ ∆. By (instinter), we have ∆ ; Γ ⊢ (λ ∧ i∈I t i →s i x.e0 ⊓ e ′ 0 )[σ id , σj]j∈J : ( i∈I ti → si) ∧ j∈J ( i∈I ti → si)σj. Finally, by (subsum), we get ∆ ; Γ ⊢ (λ ∧ i∈I t i →s i x.e0 ⊓ e ′ 0 )[σ id , σj]j∈J : i∈I ti → si. (case): consider the following derivation

. . . ∆ ; Γ ⊢ e0 : t ′      t ′ ≤ ¬t ⇒ . . . ∆ ; Γ ⊢ e1 : s t ′ ≤ t ⇒ . . . ∆ ; Γ ⊢ e2 : s ∆ ; Γ ⊢ (e0∈t ? e1 : e2) : s (case)
As erase(e ′ ) = erase(e0)∈t ? erase(e1) : erase(e2 These type-substitution inference rules are sound and complete with respect to the typing algorithm in Section C.2 in the companion paper [START_REF] Castagna | Polymorphic functions with set-theoretic types. Part 1: Syntax, semantics, and evaluation[END_REF], modulo the restriction that all the decorations in the λ-abstractions are empty.

Theorem B.13 (Soundness).

If ∆ ; Γ ⊢ I a : t, then there exists an explicitly-typed expression e ∈ E0 such that erase(e) = a and ∆ ; Γ ⊢ A e : t.

Proof. By induction on the derivation of ∆ ; Γ ⊢ I a : t. We proceed by a case analysis of the last rule used in the derivation.

′ i s ′ i ⊑ ∆∪var( i∈I t i →s i ) si ∆ ; Γ ⊢ I λ ∧ i∈I t i →s i x.a : i∈I ti → si Let ∆ ′ = ∆ ∪ var( i∈I ti → si) and [σj i ]j i ∈J i s ′ i ⊑ ∆ ′ si.
By induction, there exists an expression ei such that erase(ei) = a and ∆ ′ ; Γ, (x : ti) ⊢ A ei : s ′ i for all i ∈ I. Since σj i ♯ ∆ ′ , by (ALG-INST), we have

∆ ′ ; Γ, (x : ti) ⊢ A ei[σj i ]j i ∈J i : j i ∈J i s ′ i σj i . Clearly, ei[σj i ]j i ∈J i ♯ ∆ ′ and erase(ei[σj i ]j i ∈J i ) = erase(ei) = a.
Then by Lemma B.10, the intersection i∈I (ei[σj i ]j i ∈J i ) exists and we have erase

( i∈I ′ (ei[σj i ]j i ∈J i )) = a for any non-empty I ′ ⊆ I. Let e = i∈I (ei[σj i ]j i ∈J i ).
According to Corollary B.12, there exists a type t ′ i such that ∆ ′ ; Γ, (x : ti) ⊢ A e : t ′ i and

t ′ i ≤ j i ∈J i s ′ i σj i for all i ∈ I. Moreover, since t ′ i ≤ j i ∈J i s ′ i σj i ≤ si, by (ALG-ABSTR), we have ∆ ; Γ ⊢ A λ ∧ i∈I t i →s i
x.e : i∈I (ti → si). Finally, according to Definition B.2, we have erase(λ ∧ i∈I t i →s i x.e) = λ ∧ i∈I t i →s i x.erase(e) = λ ∧ i∈I t i →s i x.a. The proof of the soundness property constructs along the derivation for a some expression e that satisfies the statement of the theorem. We denote by erase -1 (a) the set of expressions e that satisfy the statement.

Theorem B.14 (Completeness)

. Let e ∈ E0 be an explicitly-typed expression. If ∆ ; Γ ⊢ A e : t, then there exists a type t ′ such that ∆ ; Γ ⊢ I erase(e) : t ′ and t ′ ⊑∆ t.

Proof. By induction on the typing derivation of ∆ ; Γ ⊢ A e : t. We proceed by a case analysis on the last rule used in the derivation.

(ALG-CONST): take t ′ as bc.

(ALG-VAR): take t ′ as Γ(x). (ALG-PAIR): consider the derivation . . .

∆ ; Γ ⊢ A e1 : t1 . . . ∆ ; Γ ⊢ A e2 : t2 ∆ ; Γ ⊢ A (e1, e2) : t1 × t2
Applying the induction hypothesis twice, we have

∃t ′ 1 . ∆ ; Γ ⊢ I erase(e1) : t ′ 1 and t ′ 1 ⊑∆ t1, ∃t ′ 2 . ∆ ; Γ ⊢ I erase(e2) : t ′ 2 and t ′ 2 ⊑∆ t2. Then by (INF-PAIR), we have ∆ ; Γ ⊢ I (erase(e1), erase(e2)) : t ′ 1 × t ′ 2 , that is, ∆ ; Γ ⊢ I erase((e1, e2)) : t ′ 1 × t ′ 2 . Finally, Applying Lemma B.4, we have (t ′ 1 × t ′ 2 ) ⊑∆ (t1 × t2). (ALG-PROJ): consider the derivation . . . ∆ ; Γ ⊢ A e : t t ≤ 1 × 1 ∆ ; Γ ⊢ A πi(e) : π π πi(t) By induction, we have ∃t ′ , [σ k ] k∈K . ∆ ; Γ ⊢ I erase(e) : t ′ and [σ k ] k∈K t ′ ⊑∆ t. It is clear that k∈K t ′ σ k ≤ 1 × 1. So π π πi( k∈K t ′ σ k ) ∈ ∐ i ∆ (t ′ ).
Then by (INF-PROJ), we have ∆ ; Γ ⊢ I πi(erase(e)) : π π πi( k∈K t ′ σ k ), that is, ∆ ; Γ ⊢ I erase(πi(e)) : π π πi( k∈K t ′ σ k ). According to Lemma C.5 in the companion paper [START_REF] Castagna | Polymorphic functions with set-theoretic types. Part 1: Syntax, semantics, and evaluation[END_REF], t ≤ (π π π1(t), π π π2(t)). Then k∈K t ′ σ k ≤ (π π π1(t), π π π2(t)). Finally, applying Lemma C.5 again, we get π π πi( k∈K t ′ σ k ) ≤ π π πi(t) and a fortiori π π πi( k∈K t ′ σ k ) ⊑∆ π π πi(t). (ALG-APPL): consider the derivation . . .

∆ ; Γ ⊢ A e1 : t . . . ∆ ; Γ ⊢ A e2 : s t ≤ 0 → 1 s ≤ dom(t) ∆ ; Γ ⊢ A e1e2 : t • s
Applying the induction hypothesis twice, we have

∃t ′ 1 , [σ 1 k ] k∈K 1 . ∆ ; Γ ⊢ I erase(e1) : t ′ 1 and [σ 1 k ] k∈K 1 t ′ 1 ⊑∆ t, ∃t ′ 2 , [σ 2 k ] k∈K 2 . ∆ ; Γ ⊢ I erase(e2) : t ′ 2 and [σ 2 k ] k∈K 2 t ′ 2 ⊑∆ s. It is clear that k∈K 1 t ′ 1 σ 1 k ≤ 0 → 1, that is, k∈K 1 t ′ 1 σ 1 k is a function type. So we get dom(t) ≤ dom( k∈K 1 t ′ 1 σ 1 k ). Then we have k∈K 2 t ′ 2 σ 2 k ≤ s ≤ dom(t) ≤ dom( k∈K 1 t ′ 1 σ 1 k ). Therefore, ( k∈K 1 t ′ 1 σ 1 k ) • ( k∈K 2 t ′ 2 σ 2 k ) ∈ t ′ 2 •∆ t ′ 1 .
Then applying (INF-APPL), we have ∆ ; Γ ⊢ I erase(e1)erase(e2) : (

k∈K 1 t ′ 1 σ 1 k ) • ( k∈K 2 t ′ 2 σ 2 k ), that is, ∆ ; Γ ⊢ I erase(e1e2) : ( k∈K 1 t ′ 1 σ 1 k ) • ( k∈K 2 t ′ 2 σ 2 k ). Moreover, as k∈K 2 t ′ 2 σ 2 k ≤ dom(t), t • ( k∈K 2 t ′ 2 σ 2 k ) exists.
According to Lemma C.14 in the companion paper [START_REF] Castagna | Polymorphic functions with set-theoretic types. Part 1: Syntax, semantics, and evaluation[END_REF], we have (

k∈K 1 t ′ 1 σ 1 k ) • ( k∈K 2 t ′ 2 σ 2 k ) ≤ t • ( k∈K 2 t ′ 2 σ 2 k ) ≤ t • s.
Thus,

( k∈K 1 t ′ 1 σ 1 k ) • ( k∈K 2 t ′ 2 σ 2 k ) ⊑∆ t • s. (ALG-ABSTR0): consider the derivation ∀i ∈ I. . . . ∆ ∪ var( i∈I ti → si) ; Γ, (x : ti) ⊢ A e : s ′ i and s ′ i ≤ si ∆ ; Γ ⊢ A λ ∧ i∈I t i →s i x.e : i∈I ti → si Let ∆ ′ = ∆ ∪ var( i∈I ti → si).
(e2)) : t ′ 1 ∨ t ′ 2 , that is, ∆ ; Γ ⊢ I erase(e∈t ? e1 : e2) : t ′ 1 ∨ t ′ 2 .
Using α-conversion, we can assume that the polymorphic type variables of t ′ 1 and t ′ 2 (and of e1 and e2) are distinct, i.e., (var

(t ′ 1 ) \ ∆) ∩ (var(t ′ 1 ) \ ∆) = ∅. Then applying Lemma B.5, we have t ′ 1 ∨ t ′ 2 ⊑∆ t1 ∨ t2. (ALG-INST): consider the derivation . . . ∆ ; Γ ⊢ A e : t ∀j ∈ J. σj ♯ ∆ |J| > 0 ∆ ; Γ ⊢ A e[σj]j∈J : j∈J tσj By induction, we have ∃t ′ , [σ k ] k∈K . ∆ ; Γ ⊢ I erase(e) : t ′ and [σ k ] k∈K t ′ ⊑∆ t. Since erase(e[σj]j∈J ) = erase(e), we have ∆ ; Γ ⊢ I erase(e[σj]j∈J ) : t ′ . As k∈K t ′ σ k ≤ t, we have j∈J ( k∈K t ′ σ k )σj ≤ j∈J tσj, that is k∈K,j∈J t ′ (σj • σ k ) ≤ j∈J tσj. Moreover, it is clear that σj • σ k ♯ ∆. Therefore, we get t ′ ⊑∆ j∈J tσj.
The inference system is syntax directed and describes an algorithm that is parametric in the decision procedures for ⊑∆, ∐ i ∆ (t) and t •∆ s. The problem of deciding them is tackled in Section C.2. Finally, notice that we did not give any reduction semantics for the implicitly typed calculus. The reason is that its semantics is defined in terms of the semantics of the explicitly-typed calculus: the relabeling at run-time is an essential feature -independently from the fact that we started from an explicitly typed expression or not-and we cannot avoid it. The (big-step) semantics for a is then given in expressions of erase -1 (a): if an expression in erase -1 (a) reduces to v, so does a. As we see the result of computing an implicitly-typed expression is a value of the explicitly typed calculus (so λ-abstractions may contain non-empty decorations) and this is unavoidable since it may be the result of a partial application. Also notice that the semantics is not deterministic since different expressions in erase -1 (a) may yield different results. However this may happen only in one particular case, namely, when an occurrence of a polymorphic function flows into a type-case and its type is tested. For instance the application (λ (Int→Int)→Bool f.f ∈Bool→Bool ? true : false)(λ α→α x.x) results into true or false according to whether the polymorphic identity at the argument is instantiated by

[{ Int / α }] or by [{ Int / α }, { Bool / α }].
Once more this is unavoidable in a calculus that can dynamically test the types of polymorphic functions that admit several sound instantiations.

B.3 A More Tractable Type Inference System

With the rules of Figure 5, when type-checking an implicitly-typed expression, we have to compute sets of type substitutions for projections, applications, abstractions and type cases. Because type substitutions inference is a costly operation, we would like to perform it as less as possible. To this end, we give in this section a restricted version of the inference system, which is not complete but still sound and powerful enough to be used in practice.

First, we want to simplify the type inference rule for projections:

∆ ; Γ ⊢ I a : t u ∈ ∐ i ∆ (t) ∆ ; Γ ⊢ I πi(a) : u where ∐ i ∆ (t) = {u | [σj]j∈J t ⊑∆ 1 × 1, u = π π πi( j∈J tσj)}.
Instead of picking any type in ∐ i ∆ (t), we would like to simply project t, i.e., assign the type π π πi(t) to πi(a). By doing so, we lose completeness on pair types that contain top-level variables. For example, if t = (Int × Int) ∧ α, then Int ∧ Bool ∈ ∐ i ∆ (t) (because α can be instantiated with (Bool × Bool)), but π π πt(t) = Int. We also lose typability if t is not a pair type, but can be instantiated in a pair type. For example, the type of (λ α→(α∨((β→β)\(Int→Int))) x.x)(42, 3) is (Int × Int) ∨ ((β → β) \ (Int → Int)), which is not a pair type, but can be instantiated in (Int × Int) by taking β = Int. We believe these kinds of types will not be written by programmers, and it is safe to use the following projection rule in practice.

∆ ; Γ ⊢ I a : t t ≤ 1 × 1 ∆ ; Γ ⊢ I πi(a) : π π πi(t) (INF-PROJ')
We now look at the type inference rules for the type case a∈t ? a1 : a2. The four different rules consider the different possible instantiations that make the type t ′ inferred for a fit t or not. For the sake of simplicity, we decide not to infer type substitutions for polymorphic arguments of type cases. Indeed, in the expression (λ α→α x.x) ∈ Int → Int ? true : false, we assume the programmer wants to do a type case on the polymorphic identity, and not on one of its instance (otherwise, he would have written the instantiated interface directly), so we do not try to instantiate it. And in any case there is no real reason for which the inference system should choose to instantiate the identity by Int→Int (and thus make the test succeed) rather than Bool→Bool (and thus make the test fail). If we decide not to infer types for polymorphic arguments of type-case expression, then since α → α is not a subtype of Int → Int (we have α → α ⊑ ∅ Int → Int but α → α ≤ Int → Int) the expression evaluates to false. With this choice, we can merge the different inference rules into the following one.

∆ ; Γ ⊢ I a :

t ′ t1 = t ′ ∧ t t2 = t ′ ∧ ¬t ti ≃ 0 ⇒ ∆ ; Γ ⊢ I ai : si ∆ ; Γ ⊢ I (a∈t ? a1 : a2) : t i ≃✵ si (INF-CASE')
Finally, consider the inference rule for abstractions:

∀i ∈ I.    ∆ ∪ var( i∈I ti → si) ; Γ, (x : ti) ⊢ I a : s ′ i s ′ i ⊑ ∆∪var( i∈I t i →s i ) si ∆ ; Γ ⊢ I λ ∧ i∈I t i →s i x.a : i∈I ti → si
We verify that the abstraction can be typed with each arrow type ti → si in the interface. Meanwhile, we also infer a set of type substitutions to tally the type s ′ i we infer for the body expression with si. In practice, similarly, we expect that the abstraction is well-typed only if the type s ′ i we infer for the body expression is a subtype of si. For example, the expression λ Bool→(Int→Int) x.x∈true ? (λ α→α y.y) : (λ α→α y.(λ α→α z.z)y) is not well-typed while λ Bool→(α→α) x.x∈true ? (λ α→α y.y) : (λ α→α y.(λ α→α z.z)y) is well-typed. So we use the following restricted rule for abstractions instead:

∀i ∈ I. ∆ ∪ var( i∈I ti → si) ; Γ, (x : ti) ⊢ I a : s ′ i and s ′ i ≤ si ∆ ; Γ ⊢ I λ ∧ i∈I t i →s i x.a : i∈I ti → si (INF-ABSTR')
In conclusion, we restrict the inference of type substitutions to applications. We give in Figure 6 the inference rules of the system which respects the above restrictions. With these new rules, the system remains sound, but it is not complete. Theorem B.15. If Γ ⊢ I a : t, then there exists an expression e ∈ E0 such that erase(e) = a and Γ ⊢ A e : t.

Proof. Similar to the proof of Theorem B.13.

C. Type Tallying

Given two types t and s, the goal of this section is to find pairs of sets of type-substitutions [σi]i ∈ I and [σj]j ∈ J such that j∈J sσj ≤ i∈I tσi. Assuming that the cardinalities of I and J are known, then this problem can be reduced to a type tallying problem, that we define and solve first. We then explain how we can reduce the original problem to the type tallying problem, and provide a semi-algorithm for the original problem. Finally, we give some heuristics to establish upper bounds (which depend on t and s) for the cardinalities of I and J.

C.1 Type Tallying Problem

Given a finite set C of pairs of types and a finite set ∆ of type variables, the tallying problem for C and ∆ consists in verifying whether there exists a substitution σ such that σ ♯ ∆ and for all (s, t) ∈ C, sσ ≤ tσ holds. In this section we denote constraints as triples. The notation is different from the one used in Section 3 in that it also specifies the symbol of the relation. So a pair of types (s, t) ∈ C corresponds to the constraint (s, ≤, t): c,s) is a triple belonging to T ×{≤, ≥}×T . Let C denote the set of all constraints. Given a constraint-set C ⊆ C , the set of type variables occurring in C is defined as

Definition C.1 (Constraints). A constraint (t,
var(C) = (t,c,s)∈C var(t) ∪ var(s) ∆ ; Γ ⊢ I c : bc (INF-CONST) ∆ ; Γ ⊢ I x : Γ(x) (INF-VAR) ∆ ; Γ ⊢ I a1 : t1 ∆ ; Γ ⊢ I a2 : t2 ∆ ; Γ ⊢ I (a1, a2) : t1 × t2 (INF-PAIR) ∆ ; Γ ⊢ I a : t t ≤ 1 × 1 ∆ ; Γ ⊢ I πi(a) : π π πi(t) (INF-PROJ') ∆ ; Γ ⊢ I a1 : t ∆ ; Γ ⊢ I a2 : s u ∈ t •∆ s ∆ ; Γ ⊢ I a1a2 : u (INF-APPL) ∀i ∈ I. ∆ ∪ var( i∈I ti → si) ; Γ, (x : ti) ⊢ I a : s ′ i and s ′ i ≤ si ∆ ; Γ ⊢ I λ ∧ i∈I t i →s i x.a : i∈I ti → si (INF-ABSTR') ∆ ; Γ ⊢ I a : t ′ t1 = t ′ ∧ t t2 = t ′ ∧ ¬t ti ≃ 0 ⇒ ∆ ; Γ ⊢ I ai : si ∆ ; Γ ⊢ I (a∈t ? a1 : a2) : t i ≃✵ si (INF-CASE') Figure 6. Restricted type-substitution inference rules Definition C.2 (Normalized constraint). A constraint (t, c, s) is said to be normalized if t is a type variable. A constraint-set C ⊆ C is said to be normalized if every constraint (t, c, s) ∈ C is normalized. Given a normalized constraint-set C, its domain is defined as dom(C) = {α | ∃c, s. (α, c, s) ∈ C}. Definition C.3 (Constraint solution). Let C ⊆ C be a constraint-set. A solution to C is a substitution σ such that ∀(t, ≤, s) ∈ C . tσ ≤
S1 ⊓ S2 = {C1 ∪ C2 | C1 ∈ S1, C2 ∈ S2}
Given a constraint-set C, the constraint solving algorithm produces the set of all the solutions of C by following the algorithm given in Section 3.2.1. Let us examine each step of the algorithm on some examples.

Step 1: constraint normalization.

Because normalized constraints are easier to solve than regular ones, we first turn each constraint into an equivalent set of normalized constraint-sets according to the decomposition rules in [START_REF] Castagna | Set-theoretic Foundation of Parametric Polymorphism and Subtyping[END_REF]. For example, the constraint c1

= (α × α) ≤ ((Int × 1) × (1 × Int)) can be normalized into the set S1 = {{(α, ≤, 0)}; {(α, ≤, (Int × 1)), (α, ≤, (1 × Int))}}. Another example is the constraint c2 = ((β × β) → (Int × Int), ≤, α → α), which is equivalent to the following set of normalized constraint-sets S2 = {{(α, ≤, 0)}; {(α, ≤, (β × β)), (α, ≥, (Int × Int))}}.
Then we join all the sets of constraint-sets by (constraint-set) intersections, yielding the normalization of the original constraintset. For instance, the normalization S of {c1, c2} is S1 ⊓ S2. It is easy to see that the constraint-set

C1 = {(α, ≤, (Int × 1)), (α, ≤, (1 × Int)), (α, ≤, (β × β)), (α, ≥, (Int × Int))} is in S (see Definition C.4).
Step 2: constraint merging.

Step 2.1: merge the constraints with a same type variable.

In each constraint-set of the normalization of the original constraint-set, there may be several constraints of the form (α, ≥, ti) (resp. (α, ≤, ti)), which give different lower bounds (resp. upper bounds) for α. We merge all these constraints into one using unions (resp. intersections). For example, the constraint-set C1 of the previous step can be merged as

C2 = {(α, ≤, (Int × 1) ∧ (1 × Int) ∧ (β × β)), (α, ≥, (Int × Int))}, which is equivalent to {(α, ≤, (Int ∧ β × Int ∧ β)), (α, ≥ , (Int × Int))}.
Step 2.2: saturate the lower and upper bounds of a same type variable. If a type variable has both a lower bound s and an upper bound t in a constraint-set, then the solutions we are looking for must satisfy the constraint (s, ≤, t) as well. Therefore, we have to saturate the constraint-set with (s, ≤, t), which has to be normalized, merged, and saturated itself first. Take C2 for example. We have to saturate C2 with ((Int×Int), ≤, (Int∧β×Int∧β)), whose normalization is {{(β, ≥, Int)}}. Thus, the saturation of C2 is {C2} ⊓ {{(β, ≥, Int)}}, which contains only one constraint-set C3 = {(α, ≤, (Int ∧ β × Int ∧ β)), (α, ≥, (Int × Int)), (β, ≥, Int)}.

Step 3: constraint solving.

Step 3.1: transform each constraint-set into an equation system.

To transform constraints into equations, we use the property that some set of constraints is satisfied for all assignments of α included between s and t if and only if the same set in which we replace α by (s ∨ α ′ ) ∧ t10 is satisfied for all possible assignments of α ′ (with α ′ fresh). Of course such a transformation works only if s ≤ t, but remember that we "checked" that this holds at the moment of the saturation. By performing this replacement for each variable we obtain a system of equations. For example, the constraint set C3 is equivalent to the following equation system

E: α = ((Int × Int) ∨ α ′ ) ∧ (Int ∧ β × Int ∧ β) β = Int ∨ β ′ where α ′ , β ′ are fresh type variables.
Step 3.2: extract a substitution from each equation system.

Finally, using the Courcelle's work on infinite trees [START_REF] Courcelle | Fundamental properties of infinite trees[END_REF], we solve each equation system, which gives us a substitution which is a solution of the original constraint-set. For example, we can solve the equation system E, yielding the type-substitution { (Int × Int) / α , Int ∨ β ′ / β }, which is a solution of C3 and thus of {c1, c2}.

In the following subsections we study in details each step of the algorithm.

C.1.1 Constraint Normalization

The type tallying problem is quite similar to the subtyping problem presented in [START_REF] Castagna | Set-theoretic Foundation of Parametric Polymorphism and Subtyping[END_REF]. We therefore reuse most of the technology developed in [START_REF] Castagna | Set-theoretic Foundation of Parametric Polymorphism and Subtyping[END_REF] such as, for example, the transformation of the subtyping problem into an emptiness decision problem, the elimination of top-level constructors, and so on. One of the main differences is that we do not want to eliminate top-level type variables from constraints, but, rather, we want to isolate them to build sets of normalized constraints (from which we then construct sets of substitutions).

In general, normalizing a constraint generates a set of constraints. For example, (α∨β, ≥, 0) holds if and only if (α, ≥, 0) or (β, ≥, 0) holds; therefore the constraint (α ∨ β, ≥, 0) is equivalent to the normalized constraint-set {(α, ≥, 0), (β, ≥, 0)}. Consequently, the normalization of a constraint-set C yields a set S of normalized constraint-sets.

Several normalized sets may be suitable replacements for a given constraint; for example, {(α, ≤ , β ∨ t1), (β, ≤, α ∨ t2)} and {(α, ≤, β ∨ t1), (α, ≥, β \ t2)} are clearly equivalent normalized sets. However, the equation systems generated by the algorithm for these two sets are completely different, and different equation systems yield different substitutions (see Section C.1.3 for more details). Concretely, {(α, ≤, β ∨ t1), (β, ≤, α ∨ t2)} generates the equation system {α = α ′ ∧ (β ∨ t1), β = β ′ ∧ (α ∨ t2)}, which in turn gives the substitution σ1 such that

σ1(α) = µx. ((α ′ ∧ β ′ ∧ x) ∨ (α ′ ∧ β ′ ∧ t2) ∨ (α ′ ∧ t1)) σ1(β) = µx. ((β ′ ∧ α ′ ∧ x) ∨ (β ′ ∧ α ′ ∧ t1) ∨ (β ′ ∧ t2))
where α ′ and β ′ are fresh type variables and we used the µ notation to denote regular recursive types. These recursive types are not valid in our calculus, because x does not occur under a type constructor (this means that the unfolding of the type does not satisfy the property that every infinite branch contains infinitely many occurrences of type constructors). In contrast, the equation system built from {(α, ≤,

β ∨t1), (α, ≥, β \t2)} is α = ((β \ t2) ∨ α ′ ) ∧ (β ∨ t1), and the corresponding substitution is σ2 = { ((β \ t 2 ) ∨ α ′ ) ∧ (β ∨ t 1 ) / α },
which is valid since it maps the type variable α into a well-formed type. Ill-formed recursive types are generated when there exists a chain α0 = α1 B1 t1, . . . , αi = αi+1 Bi+1 ti+1, . . . , αn = α0 Bn+1 tn+1 (where Bi ∈ {∧, ∨} for all i, and n ≥ 0) in the equation system built from the normalized constraintset. This chain implies the equation α0 = α0 B t ′ for some B ∈ {∧, ∨} and t ′ , and the corresponding solution for α0 will be an ill-formed recursive type. To avoid this issue, we give an arbitrary ordering on type variables occurring in the constraint-set C such that different type variables have different orders. Then we always select the normalized constraint (α, c, t) such that the order of α is smaller than all the orders of the top-level type variables in t. As a result, the transformed equation system does not contain any problematic chain like the one above.

Definition C.5 (Ordering). Let V be a set of type variables. An ordering O on V is an injective map from V to N.

We formalize normalization as a judgement Σ ⊢ N C S , which states that under the environment Σ (which, informally, contains the types that have already been processed at this point), C is normalized to S . The judgement is derived according the rules of Figure 7. These rules describe the same algorithm as the function norm given in Figure 3 (ie, Σ ⊢ N {(t, ≤, 0)} norm(t, Σ) is provable in the system of Figure 7) but extended to handle also product types. We just switched to a deduction systems since it eases the formal treatment.

Σ ⊢ N ∅ {∅} (NEMPTY) Σ ⊢ N {(ti ci t ′ i )} Si Σ ⊢ N {(ti ci t ′ i ) | i ∈ I} i∈I Si (NJOIN) Σ ⊢ N {(t ≤ t ′ )} S Σ ⊢ N {(t ′ ≥ t)} S (NSYM) Σ ⊢ N {(t ∧ ¬t ′ ≤ 0)} S t ′ = 0 Σ ⊢ N {(t ≤ t ′ )} S (NZERO) Σ ⊢ N {(dnf(t) ≤ 0)} S Σ ⊢ N {(t ≤ 0)} S (NDNF) Σ ⊢ N {(τi ≤ 0) | i ∈ I} S Σ ⊢ N {( i∈I τi ≤ 0)} S (NUNION) tlv(τ0) = ∅ α ′ O P ∪ N S = {{(α ′ , ≤, ¬t α ′ )}} α ′ ∈ P {{(α ′ , ≥, t α ′ )}} α ′ ∈ N Σ ⊢ N {( α∈P α ∧ α∈N ¬α ∧ τ0 ≤ 0)} S (NTLV) τ0 ∈ Σ tlv(τ0) = ∅ Σ ⊢ N {(τ0 ≤ 0)} {∅} (NHYP) Σ ∪ {τ0} ⊢ * N {(τ0 ≤ 0)} S τ0 / ∈ Σ tlv(τ0) = ∅ Σ ⊢ N {(τ0 ≤ 0)} S (NASSUM) i∈P bi ∧ j∈N ¬bj ≤ 0 Σ ⊢ * N {( i∈P bi ∧ j∈N ¬bj ≤ 0)} {∅} (NBASIC-T) i∈P bi ∧ j∈N ¬bj 0 Σ ⊢ * N {( i∈P bi ∧ j∈N ¬bj ≤ 0)} ∅ (NBASIC-F) ∀N ′ ⊆ N.          Σ ⊢ N { i∈P t 1 i ∧ j∈N ′ ¬t 1 j ≤ 0} S 1 N ′ Σ ⊢ N { i∈P t 2 i ∧ j∈N \N ′ ¬t 2 j ≤ 0} S 2 N ′ Σ ⊢ * N {( i∈P (t 1 i × t 2 i ) ∧ j∈N ¬(t 1 j × t 2 j ) ≤ 0)} N ′ ⊆N (S 1 N ′ ⊔ S 2 N ′ ) (NPROD) ∃j ∈ N ∀P ′ ⊆ P.              Σ ⊢ N {t 1 j ∧ i∈P ′ ¬t 1 i ≤ 0} S 1 P ′      Σ ⊢ N { i∈P \P ′ t 2 i ∧ ¬t 2 j ≤ 0} S 2 P ′ P ′ = P S 2 N ′ = ∅ otherwise Σ ⊢ * N {( i∈P (t 1 i → t 2 i ) ∧ j∈N ¬(t 1 j → t 2 j ) ≤ 0)} j∈N P ′ ⊆P (S 1 P ′ ⊔ S 2 P ′ ) (NARROW)
where t and t with scripts are types, ci belongs to {≤, ≥}, τ0 and τi are single normal forms, α O P ∪ N denotes α has the smallest order in P ∪ N under the ordering O, and t α ′ is the type obtained from α∈P α ∧ α∈N ¬α ∧ τ0 by eliminating α ′ .

Figure 7. Normalization rules

If the constraint-set is empty, then clearly any substitution is a solution, and, the result of the normalization is simply the singleton containing the empty set (rule (NEMPTY)). Otherwise, each constraint is normalized separately, and the normalization of the constraint-set is the intersection of the normalizations of each constraint (rule (NJOIN)). By using rules (NSYM), (NZERO), and (NDNF) repeatedly, we transform any constraint into the constraint of the form (τ, ≤, 0) where τ is disjunctive normal form: the first rule reverses (t ′ , ≥, t) into (t, ≤, t ′ ), the second rule moves the type t ′ from the right of ≤ to the left, yielding (t ∧ ¬t ′ , ≤, 0), and finally the last rule puts t ∧ ¬t ′ in disjunctive normal form. Such a type τ is the type to be normalized. If τ is a union of single normal forms, the rule (NUNION) splits the union of single normal forms into constraints featuring each of the single normal forms. Then the results of each constraint normalization are joined by the rule (NJOIN).

The following rules handle constraints of the form (τ, ≤, 0), where τ is a single normal form. If there are some top-level type variables, the rule (NTLV) generates a normalized constraint for the top-level type variable whose order is the smallest. Otherwise, there are no top-level type variables. If τ has already been normalized (i.e., it belongs to Σ), then it is not processed again (rule (NHYP)). Otherwise, we memoize it and then process it using the predicate for single normal forms Σ ⊢ * N C S (rule (NASSUM)). Note that switching from Σ ⊢ N C S to Σ ⊢ * N C S prevents the incorrect use of (NHYP) just after (NASSUM), which would wrongly say that any type is normalized without doing any computation.

Finally, the last four rules state how to normalize constraints of the form (τ, ≤, 0) where τ is a single normal form and contains no top-level type variables. Thereby τ should be an intersection of atoms with the same constructor. If τ is an intersection of basic types, normalizing is equivalent to checking whether τ is empty or not: if it is (rule (NBASIC-T)), we return the singleton containing the empty set (any substitution is a solution), otherwise there is no solution and we return the empty set (rule (NBASIC-F)). When τ is an intersection of products, the rule (NPROD) decomposes τ into several candidate types (following Lemma 3.11 in [START_REF] Castagna | Set-theoretic Foundation of Parametric Polymorphism and Subtyping[END_REF]), which are to be further normalized. The case when τ is an intersection of arrows (rule (NARROW)) is treated similarly. Note that, in the last two rules, we switch from Σ ⊢ * N C S back to Σ ⊢ N C S in the premises to ensure termination. If ∅ ⊢ N C S , then S is the result of the normalization of C. We now prove soundness, completeness, and termination of the constraint normalization algorithm.

To prove soundness, we use a family of subtyping relations ≤n that layer ≤ 11 (i.e., such that n∈N ≤n=≤) and a family of satisfaction predicates n that layer (i.e., such that n∈N n= ), which are defined as follows.

     i∈I ti ≤n j∈J ′ tj ∨ i∈I si ≤n j∈J\J ′ sj (4) i∈I (ti → si) ≤n+1 j∈J (tj → sj) ⇐⇒ ∃j0∈J . ∀I ′ ⊆I .              tj 0 ≤n i∈I ′ ti ∨      I = I ′ ∧ i∈I\I ′ si ≤n sj 0 Proof. (1) straightforward.
(2) straightforward.

(3) the result follows by Lemma 3.11 in [START_REF] Castagna | Set-theoretic Foundation of Parametric Polymorphism and Subtyping[END_REF] and Definition C.6. (4) the result follows by Lemma 3.12 in [START_REF] Castagna | Set-theoretic Foundation of Parametric Polymorphism and Subtyping[END_REF] and Definition C. Before proving these statements, we explain how the first property implies the lemma. Suppose ∅ ⊢ N C S , C ′ ∈ S and σ C ′ . It is easy to check that σ n C(∅) holds for all n. From σ C ′ , we deduce σ n C ′ for all n (by Lemma C.9). By Property (1), we have σ n C for all n, and we have then the required result by Lemma C.9.

We prove these two properties simultaneously by induction on the derivations of Σ ⊢ N C S and Σ ⊢ *

C ′ = N ′ ⊆N C N ′ , where C N ′ ∈ (S 1 N ′ ⊔ S 2 N ′ ). Since σ n C ′ , we have σ n C N ′ for all subset N ′ ⊆ N . Moreover, following Definition C.4, either C N ′ ∈ S 1 N ′ or C N ′ ∈ S 2 N ′ . By induction, we have either σ n { i∈P t 1 i ∧ j∈N ′ ¬t 1 j ≤ 0} or σ n { i∈P t 2 i ∧ j∈N \N ′ ¬t 2 j ≤ 0}. That is, for all subset N ′ ⊆ N , we have i∈P t 1 i σ ∧ j∈N ′ ¬t 1 j σ ≤n 0 or i∈P t 2 i σ ∧ j∈N \N ′ ¬t 2 j σ ≤n 0 Applying Lemma C.7, we have i∈P (t 1 i × t 2 i )σ ∧ j∈N ¬(t 1 j × t 2 j )σ ≤n+1 0 Thus, σ n+1 {( i∈P (t 1 i × t 2 i ) ∧ j∈N ¬(t 1 j × t 2 j ) ≤ 0)}.
(NARROW): similar to the case of (NPROD).

Given a normalized constraint-set C and a set X of type variables, we define the restriction C|X of C by X to be {(α, c, t) ∈ C | α ∈ X}.

Lemma C.11. Let t be a type and ∅ ⊢ N {(t, ≤, 0)} S . Then for all normalized constraint-set C ∈ S , all substitution σ and all n, if σ n C| tlv(t) and σ n-1 C \ C| tlv(t) , then σ n {(t, ≤, 0)}.

Proof. By applying the rules (NDNF) and (NUNION), the constraint-set {(t, ≤, 0)} is normalized into a new constraint-set C ′ , consisting of the constraints of the form (τ, ≤, 0), where τ is a single normal form. That is, ∅ ⊢ N {(t, ≤, 0)}

{C ′ }. Let C ′ 1 = {(τ, ≤, 0) ∈ C ′ | tlv(τ ) = ∅} and C ′ 2 = C ′ \ C ′ 1 .
It is easy to deduce that all the constraints in C \ C| tlv(t) are generated from C ′ 2 and must pass at least one instance of ⊢ * N (i.e., being decomposed at least once). Since σ n-1 C \ C| tlv(t) , then according to the statement (2) in the proof of Lemma C. (NDNF): similar to the case of (NZERO). (NUNION): similar to the case of (NZERO). (NTLV): assume α ′ has the smallest order in P ∪ N . If α ′ ∈ P , then according to set-theory, we have

α ′ σ ≤ ¬( α∈(P \{α ′ }) α ∧ α∈N ¬α ∧ τ0), that is σ {(α ′ ≤ ¬t α ′ )}.
{( i∈P (t 1 i × t 2 i ) ∧ j∈N ¬(t 1 j × t 2 j ) ≤ 0)} we have i∈P (t 1 i × t 2 i )σ ∧ j∈N ¬(t 1 j × t 2 j )σ ≤ 0
Applying Lemma 3.11 in [START_REF] Castagna | Set-theoretic Foundation of Parametric Polymorphism and Subtyping[END_REF], for all subset N ′ ⊆ N , we have

i∈P t 1 i σ ∧ j∈N ′ ¬t 1 j σ ≤ 0 or i∈P t 2 i σ ∧ j∈N \N ′ ¬t 2 j σ ≤ 0 that is, σ {( i∈P t 1 i ∧ j∈N ′ ¬t 1 j ≤ 0)} or σ {( i∈P t 2 i ∧ j∈N \N ′ ¬t 2 j ≤ 0)} By induction, either there exists C 1 N ′ ∈ S 1 N ′ such that σ C 1 N ′ or there exists C 2 N ′ ∈ S 2 N ′ such that σ C 2 N ′ . According to Definition C.4, we have C 1 N ′ , C 2 N ′ ∈ S 1 N ′ ⊔ S 2 N ′ . Thus there exists C ′ N ′ ∈ S 1 N ′ ⊔S 2 N ′ such that σ C ′ N ′ . Therefore σ N ′ ⊆N C ′ N ′ . Moreover, according to Definition C.4 again, N ′ ⊆N C ′ N ′ ∈ N ′ ⊆N (S 1 N ′ ⊔ S 2 N ′ ).
Hence, the result follows. (NARROW): similar to the case (NPROD) except we use Lemma 3.12 in [START_REF] Castagna | Set-theoretic Foundation of Parametric Polymorphism and Subtyping[END_REF].

We now prove termination of the algorithm.

Definition C.13 (Plinth).

A plinth ⊂ T is a set of types with the following properties:

• is finite;

• contains 1, 0 and is closed under Boolean connectives (∧, ∨, ¬);

• for all types (t1 × t2) or (t1 → t2) in , we have t1 ∈ and t2 ∈ .

As stated in [START_REF] Frisch | Théorie, conception et réalisation d'un langage de programmation fonctionnel adapté à XML[END_REF], every finite set of types is included in a plinth. Indeed, we already know that for a regular type t the set of its subtrees S is finite. The definition of the plinth ensures that the closure of S under Boolean connective is also finite. Moreover, if t belongs to a plinth , then the set of its subtrees is contained in . This is used to show the termination of algorithms working on types.

Lemma C.14 (Termination). Let C be a finite constraint-set. Then the normalization of C terminates.

Proof. Let T be the set of type occurring in C. As C is finite, T is finite as well. Let be a plinth such that T ⊆ . Then when we normalize a constraint (t ≤ 0) during the process of ∅ ⊢ N C, t would belong to . We prove the lemma by induction on (| \ Σ|, U, |C|) lexicographically ordered, where Σ is the set of types we have normalized, U is the number of unions ∨ occurring in the constraint-set C plus the number of constraints (t, ≥, s) and the number of constraint (t, ≤, s) where s = 0 or t is not in disjunctive normal form, and C is the constraint-set to be normalized. Proof. The only way to generate normalized constraints is Rule (NTLV), where we have selected the normalized constraint for the type variable α whose order is minimum as the representative one, that is, ∀β ∈ tlv(tα) . O(α) < O(β). Therefore, the result follows.

Definition C.18. A general renaming ρ is a special type substitution that maps each type variable to another (fresh) type variable.

Lemma C.19. Let t, s be two types and [ρi]i∈I , [ρj]j∈J two sets of general renamings. Then if ∅ ⊢ N {(s ∧ t, ≤, 0)} ∅, then ∅ ⊢ N {(( j∈J sρj) ∧ ( i∈I tρi), ≤, 0)} ∅.

Proof. By induction on the number of (NPROD) and (NARROW) used in the derivation of ∅ ⊢ N {(s ∧ ¬t, ≤ , 0)} and by cases on the disjunctive normal form τ of s∧¬t. The failure of the normalization of (s∧t, ≤, 0) is essentially due to (NBASIC-F), (NPROD) and (NARROW), where there are no top-level type variables to make the type empty.

The case of arrows is a little complicated, as we need to consider more than two types: one type for the negative parts and two types for the positive parts from t and s respectively. Indeed, what we prove is the following stronger statement:

∅ ⊢ N {( k∈K t k , ≤, 0)} ∅ =⇒ ∅ ⊢ N {( k∈K ( i k ∈I k t k ρi k ), ≤, 0)} ∅
where |K| ≥ 2 and ρi k 's are general renamings. For simplicity, we only consider |K| = 2, as it is easy to extend to the case of |K| > 2.

Case 1: τ = τ bs ∧ τ b t and τ ≃ 0, where τ bs (τ b t resp.) is an intersection of basic types from s (t resp.). Then the expansion of τ is The type tallying problem is parameterized with a set ∆ of type variables that cannot be instantiated, but so far, we have not considered these monomorphic variables in the normalization procedure. Taking ∆ into account affects only the (NTLV) rule, where a normalized constraint is built by singling out a variable α. Since the type substitution σ we want to construct must not touch the type variables in ∆ (i.e., σ ♯ ∆), we cannot choose a variable α in ∆. To avoid this, we order the variables in C so that those belonging to ∆ are always greater than those not in ∆. If, by choosing the minimum top-level variable α, we obtain α ∈ ∆, it means that all the top-level type variables are contained in ∆. According to Lemmas C.3 and C.11 in the companion paper [START_REF] Castagna | Polymorphic functions with set-theoretic types. Part 1: Syntax, semantics, and evaluation[END_REF], we can then safely eliminate these type variables. So taking ∆ into account, we amend the (NTLV) rule as follows.

( j∈J τ bs ρj) ∧ ( i∈I τ b t ρi) ≃ τ bs ∧ τ b t ≃ 0 So ∅ ⊢ N {(( j∈J τ bs ρj) ∧ ( i∈I τ b t ρi), ≤, 0)} ∅.
P ′ t ⊆ Pt such that        ∅ ⊢ N { ps∈P ′ s ¬wp s ∧ p t ∈P ′ t ¬wp t ∧ w, ≤, 0)} ∅ P ′ s = Ps ∧ P ′ t = Pt or ∅ ⊢ N { ps∈Ps\P ′ s vp s ∧ p t ∈P t \P ′ t vp t ∧ ¬v, ≤, 0)} ∅ By induction, for all ρ ∈ [ρi]i∈I ∪ [ρj]j∈J , we have                  ∅ ⊢ N { j∈J ( ps∈P ′ s ¬wp s )ρj ∧ i∈I ( p t ∈P ′ t ¬wp t )ρi ∧ wρ, ≤, 0)} ∅        P ′ s = Ps ∧ P ′ t =
tlv(τ0) = ∅ α ′ O P ∪ N S =      {{(α ′ , ≤, ¬t α ′ )}} α ′ ∈ P \ ∆ {{(α ′ , ≥, t α ′ )}} α ′ ∈ N \ ∆ Σ ⊢ N {(τ0 ≤ 0)} α ′ ∈ ∆ Σ ⊢ N {( α∈P α ∧ α∈N ¬α ∧ τ0 ≤ 0)} S (NTLV)
Furthermore, it is easy to prove the soundness, completeness, and termination of the algorithm extended with ∆.

C.1.2 Constraint merging

A normalized constraint-set may contain several constraints for a same type variable, which can eventually be merged together. For instance, the constraints α ≥ t1 and α ≥ t2 can be replaced by α ≥ t1 ∨ t2, and the constraints α ≤ t1 and α ≤ t2 can be replaced by α ≤ t1 ∧ t2. That is to say, we can merge all the lower bounds (resp. upper bounds) of a type variable into only one by unions (resp. intersections).

∀i ∈ I . (α ≥ ti) ∈ C |I| ≥ 2 ⊢ M C (C \ {(α ≥ ti) | i ∈ I}) ∪ {(α ≥ i∈I ti)} (MLB) ∀i ∈ I . (α ≤ ti) ∈ C |I| ≥ 2 ⊢ M C (C \ {(α ≤ ti) | i ∈ I}) ∪ {(α ≤ i∈I ti)} (MUB) Figure 8. Merging rules
After repeated uses of the merging rules, a set C contains at most one lower bound constraint and at most one upper bound constraint for each type variable. If both lower and upper bounds exist for a given α, that is, α ≥ t1 and α ≤ t2 belong to C, then the substitution we want to construct from C must satisfy the constraint (t1, ≤, t2) as well. For that, we first normalize the constraint (t1, ≤, t2), yielding a set of constraint-sets S , and then saturate C with any normalized constraint-set C ′ ∈ S . Formally, we describe the saturation process as the saturation rule Σp, CΣ ⊢ S C S , where Σp is a set of type pairs (if (t1, t2) ∈ Σp, then the constraint t1 ≤ t2 has already been treated at this point), CΣ is a normalized constraint-set (which collects the treated original constraints, like (α, ≥, t1) and (α, ≤, t2), that generate the additional constraints), C is the normalized constraint-set we want to saturate, and S is a set of sets of normalized constraints (the result of the saturation of C joined with CΣ). The saturation rules are given in Figure 9, which describe the same algorithm as Step 2 of the function merge given in Subsection 3.2.1.

Σp, CΣ ∪ {(α ≥ t1), (α ≤ t2)} ⊢ S C S (t1, t2) ∈ Σp Σp, CΣ ⊢ S {(α ≥ t1), (α ≤ t2)} ∪ C S (SHYP) (t1, t2) / ∈ Σp ∅ ⊢ N {(t1 ≤ t2)} S S ′ = {{(α ≥ t1), (α ≤ t2)} ∪ C ∪ CΣ} ⊓ S ∀C ′ ∈ S ′ . Σp ∪ {(t1, t2)}, ∅ ⊢ M S C ′ S C ′ Σp, CΣ ⊢ S {(α ≥ t1), (α ≤ t2)} ∪ C C ′ ∈S ′ S C ′ (SASSUM) ∀α, t1, t2 ∄{(α ≥ t1), (α ≤ t2)} ⊆ C Σp, CΣ ⊢ S C {C ∪ CΣ} (SDONE)
where Σp, CΣ ⊢ M S C S means that there exists C ′ such that ⊢ M C C ′ and Σp, CΣ ⊢ S C ′ S .

Figure 9. Saturation rules

If α ≥ t1 and α ≤ t2 belongs to the constraint-set C that is being saturated, and t1 ≤ t2 has already been processed (i.e., (t1, t2) ∈ Σp), then the rule (SHYP) simply extends CΣ (the result of the saturation so far) with {α ≥ t1, α ≤ t2}. Otherwise, the rule (SASSUM) first normalizes the fresh constraint {t1 ≤ t2}, yielding a set of normalized constraint-sets S . It then saturates (joins) C and CΣ with each constraint-set C S ∈ S , the union of which gives a new set S ′ of normalized constrain-sets. Each C ′ in S ′ may contain several constraints for the same type variable, so they have to be merged and saturated themselves. Finally, if C does not contain any couple α ≥ t1 and α ≤ t2 for a given α, the process is over and the rule (SDONE) simply returns C ∪ CΣ.

If

= k b ∈K b τ k b ∨ kp∈Kp τ kp ∨ ka∈Ka τ ka
where τ k b (τ kp and τ ka resp.) is an intersection of basic types (products and arrows resp.) and type variables. Then there must exist k

∈ K b ∪ Kp ∪ Ka such that ∅ ⊢ N {(τ k , ≤, 0 → 1)} ∅. If k ∈ K b ∪ Kp, then the constraint (τ k , ≤, s → γ) is equivalent to (τ k , ≤, 0). By Lemma C.19, we get ∅ ⊢ N {( i∈I τ k ρi, ≤, 0)} ∅, that is, ∅ ⊢ N {( i∈I τ k ρi, ≤, ( j∈J sρj) → γ)} ∅. So the result follows. Otherwise, it must be that k ∈ Ka and τ k = p∈P (wp → vp) ∧ n∈N ¬(wn → vn). We claim that ∅ ⊢ N {(τ k , ≤, 0)} ∅ (otherwise, ∅ ⊢ N {(τ k , ≤, s → γ)} ∅ does not hold). Applying Lemma C.19 again, we get ∅ ⊢ N {( i∈I τ k ρi, ≤, 0)} ∅.
Moreover, following the rule (NARROW), there exists a set Let App ∆ (t, s) denote the semi-algorithm for the general application problem.

P ′ ⊆ P such that        ∅ ⊢ N { p∈P ′ ¬wp ∧ s, ≤, 0)} ∅ P ′ = P or ∅ ⊢ N { p∈P \P ′ vp ∧ ¬γ, ≤, 0)} ∅ Applying C.19, we get        ∅ ⊢ N { i∈I ( p∈P ′ ¬wp)ρi ∧ j∈J sρj, ≤, 0)} ∅ P ′ = P or ∅ ⊢ N { i∈I ( p∈P \P ′ vp)ρi ∧ ¬γ, ≤ ,
Theorem C.54. Let t, s be two types and γ the special fresh type variable introduced in Consider the application map even, whose types are

( i∈I tσi, ≤ , ( j∈J sσj) → γ). If App ∆ (t, s) terminates with Θ, then (1) (Soundness) if Θ = ∅, then for each σ ∈ Θ, σ(γ) ∈ t •∆ s. ( 2
) (Weak completeness) if Θ = ∅, then t •∆ s = ∅. Proof. ( 1
map :: (α → β) → [α] → [β] even :: (Int → Bool) ∧ ((α \ Int) → (α \ Int)) We start with the constraint-set C1 = {(α1 → β1) → [α1] → [β1] ≤ ((Int → Bool) ∧ ((α \ Int) → (α \ Int))) → γ}
where γ is a fresh type variable (and where we α-converted the type of map). Then the algorithm Sol∆(C1) generates a set of eight constraint-sets at Step 2 :

{γ ≥

[α1] → [β1], α1 ≤ 0} {γ ≥ [α1] → [β1], α1 ≤ 0, β1 ≥ Bool} {γ ≥ [α1] → [β1], α1 ≤ 0, β1 ≥ α \ Int} {γ ≥ [α1] → [β1], α1 ≤ 0, β1 ≥ Bool ∨ (α \ Int)} {γ ≥ [α1] → [β1], α1 ≤ 0, β1 ≥ Bool ∧ (α \ Int)} {γ ≥ [α1] → [β1], α1 ≤ Int, β1 ≥ Bool} {γ ≥ [α1] → [β1], α1 ≤ α \ Int, β1 ≥ α \ Int} {γ ≥ [α1] → [β1], α1 ≤ Int ∨ α, β1 ≥ Bool ∨ (α \ Int)}
Clearly, the solutions to the 2nd-5th constraint-sets are included in those to the first constraint-set. For the other four constraint-sets, by minimum instantiation, we can get four solutions for γ (i.e., the result types of map even):

[ ] → [ ], or [Int] → [Bool], or [α \ Int] → [α \ Int], or [Int ∨ α] → [Bool ∨ (α \ Int)].
Of these solutions only the last two are minimal (the first type is an instance of the third one and the second is an instance of the fourth one) and since both are valid we can take their intersection, yielding the (minimum) solution

([α \ Int] → [α \ Int]) ∧ ([Int ∨ α] → [Bool ∨ (α \ Int)]) (20
) Alternatively, we can dully follow the algorithm, perform an iteration, expand the type of the function, yielding the constraint-set

{((α1 → β1) → [α1] → [β1]) ∧ ((α2 → β2) → [α2] → [β2]) ≤ ((Int → Bool) ∧ ((α \ Int) → (α \ Int)))
→ γ} from which we get the type (20) directly.

As stated in Section C.1, we chose an arbitrary ordering on type variables, which affects the generated substitutions and then the resulting types. Assume that σ1 and σ2 are two type substitutions generated by different orders. Thanks to the completeness of the tallying problem, there exist σ ′ 1 and σ ′ 2 such that σ2 ≃ σ ′ 1 • σ1 and σ1 ≃ σ ′ 2 • σ2. Therefore, the result types corresponding to σ1 and σ2 are equivalent under ⊑∆, that is σ1(γ) ⊑∆ σ2(γ) and σ2(γ) ⊑∆ σ1(γ). However, this does not imply that σ1(γ) ≃ σ2(γ). For example, α ⊑∆ 0 and 0 ⊑∆ α, but α ≃ 0. Moreover, some result types are easier to understand or more precise than some others. Which one is better is a language design and implementation problem 14 . For example, consider the map even again. The type ( 20) is obtained under the ordering o(α1) < o(β1) < o(α). While under the ordering o(α) < o(α1) < o(β1), we would instead get [START_REF] Pierce | Local type inference[END_REF]. However, compared with (20), ( 21) is less precise and less comprehensible, if we look at the type [Int ∨ Bool ∨ β] → [Bool ∨ β] : (1) there is a Bool in the domain which is useless here and (2) we know that Int cannot appear in the returned list, but this is not expressed in the type.

([β \ Int] → [β]) ∧ ([Int ∨ Bool ∨ β] → [Bool ∨ β]) (21
There is a final word on completeness, which states that for every solution of the application problem, our algorithm finds a solution that is more general. However this solution is not necessarily the first one found by the algorithm: even if we find a solution, continuing with a further expansion may yield a more general solution. We have just seen that, in the case of map even, the good solution is the second one, although this solution could have already been deduced by intersecting the first minimal solutions we found. Another simple example is the case of the application of a function of type (α × β) → (β × α) to an argument of type (Int×Bool) ∨ (Bool×Int). For this application our algorithm returns after one iteration the type (Int∨Bool) × (Int∨Bool) (since it unifies α with β) while one further iteration allows the system to deduce the more precise type (Int×Bool)∨(Bool×Int). Of course this raises the problem of the existence of principal types: may an infinite sequence of increasingly general solutions exist? This is a problem we did not tackle in this work, but if the answer to the previous question were negative then it would be easy to prove the existence of a principal type: since at each iteration there are only finitely many solutions, then the principal type would be the intersection of the minimal solutions of the last iteration (how to decide that an iteration is the last one is yet another problem).

C.2.3 Heuristics to stop type-substitution inference

We only have a semi-algorithm for t •∆s because, as long as we do not find a solution, we may increase the cardinalities of I and J (where I and J are defined as in the previous sections) indefinitely. In this section, we propose two heuristic numbers p and q for the cardinalities of I and J that are established according to the form of s and t. These heuristic numbers set the upper limit for the procedure: if no solution is found when the cardinalities of I and J have reached these heuristic numbers, then the procedure stops returning failure. This yields a terminating algorithm for t •∆ s which is clearly sound but, in our case, not complete. Whether it is possible to define these boundaries so that they ensure termination and completeness is still an open issue.

Through some examples, we first analyze the reasons why one needs to expand the function type t and/or the argument type s: the intuition is that type connectives are what makes the expansions necessary. Then based on this analysis, we give some heuristic numbers for the copies of types that are needed by the expansions. These heuristics follow some simple (but, we believe, reasonable) guidelines. First, when the substitutions found for a given p and q yield a useless type (e.g., "0 → 0" the type of a function that cannot be applied to any value), it seems sensible to expand the types (i.e., increase p or q), in order to find more informative substitutions. Second, if iterating the process does not give a more precise type (in the sense of ⊑), then it seems sensible to stop. Last, when the process continuously yields more and more precise types, we choose to stop when the type is "good enough" for the programmer. In particular we choose to avoid to introduce too many new fresh variables that make the type arbitrarily more precise but at the same time less "programmer friendly". We illustrate these behaviours for three strategies: increasing p (that is, expanding the domain of the function), increasing q (that is, expanding the type of the argument) or lastly increasing both p and q at the same time.

Expansion of t.

A simple reason to expand t is the presence of (top-level) unions in s. Generally, it is better to have as many copies of t as there are disjunctions in s. Consider the example,

t = (α → α) → (α → α) s = (Int → Int) ∨ (Bool → Bool) (22)
If we do not expand t (ie, if p is 1), then the result type computed for the application of t to s is 0 → 0. However, this result type cannot be applied hereafter, since its domain is 0, and is therefore useless (more precisely, it can be applied only to expressions that are provably diverging). When p is 2, we get an extra result type, (Int → Int) ∨ (Bool → Bool), which is obtained by instantiating t twice, by Int and Bool respectively. Carrying on expanding t does not give more precise result types, as we always select only two copies of t to match the two summands in s, according to the decomposition rule for arrows [START_REF] Castagna | Set-theoretic Foundation of Parametric Polymorphism and Subtyping[END_REF].

A different example that shows that the cardinality of the summands in the union type of the argument is a good heuristic choice for p is the following one:

t = (α × β) → (β × α) s = (Int × Bool) ∨ (Bool × Int) (23)
Without expansion, the result type is ((Int ∨ Bool) × (Bool ∨ Int)) (α unifies Int and Bool). If we expand t, there exists a more precise result type (Int × Bool) ∨ (Bool × Int), each summand of which corresponds to a different summand in s. Besides, due to the decomposition rule for product types [START_REF] Castagna | Set-theoretic Foundation of Parametric Polymorphism and Subtyping[END_REF], there also exist some other result types which involve type variables, like ((Int ∨ Bool) × α) ∨ ((Int ∨ Bool) × (Int ∨ Bool) \ α). Further expanding t makes more product decompositions possible, which may in turn generate new result types. However, the type (Int × Bool) ∨ (Bool × Int) is informative enough, and so we set the heuristic number to 2, that is, the number of summands in s.

We may have to expand t also because of intersection. First, suppose s is an intersection of basic types; it can be viewed as a single basic type. Consider the example t = α → (α × α) and s = Int (24) Without expansion, the result type is γ1 = (Int × Int). With two copies of t, besides γ1, we get another result type γ2 = (β × β) ∨ (Int \ β × Int \ β), which is more general than γ1 (eg, γ1 = γ2{ 0 / β }). Generally, with k copies, we get k result types of the form

γ k = (β1 × β1) ∨ . . . ∨ (β k-1 × β k-1 ) ∨ (Int \ ( i=1..k-1 βi) × Int \ ( i=1..k-1 βi)) It is clear that γ k+1 ⊑ ∅ γ k . Moreover, it is easy to find two substitutions [σ1, σ2] such that [σ1, σ2] γ k ⊑ ∅ γ k+1 (k ≥ 2)
. Therefore, γ2 is the minimum (with respect to ⊑ ∅ ) of {γ k , k ≥ 1}, so expanding t more than once is useless (we do not get a type more precise than γ2). However, we think the programmer expects (Int × Int) as a result type instead of γ2. So we take the heuristic number here as 1.

An intersection of product types is equivalent to i∈I (s i 1 × s i 2 ), so we consider just a single product type (and then use union for the general case). For instance,

t = ((α → α) × (β → β)) → ((β → β) × (α → α)) s = (((Even → Even) ∨ (Odd → Odd)) × (Bool → Bool)) (25)
For the application to succeed, we have a constraint generated for each component of the product type, namely (α → α ≥ (Even → Even) ∨ (Odd → Odd)) and (β → β ≥ Bool → Bool). As with Example [START_REF] Tobin-Hochstadt | The design and implementation of typed scheme[END_REF], it is better to expand α → α once for the first constraint, while there is no need to expand β → β for the second one. As a result, we expand the whole type t once, and get the result type ((Bool → Bool) × ((Even → Even) ∨ (Odd → Odd))) as expected. Generally, if the heuristic numbers of the components of a product type are respectively p1 and p2, we take p1 * p2 as the heuristic number for the whole product. Finally, suppose s is an intersection of arrows, like for example map even.

t = (α → β) → [α] → [β] s = (Int → Bool) ∧ ((γ \ Int) → (γ \ Int)) (26)
When p = 1, the constraint to solve is (α → β ≥ s). As stated in Subsection C.2.2, we get four possible result types:

[ ] → [ ], [Int] → [Bool], [α \ Int] → [α \ Int], or [Int ∨ α] → [Bool ∨ (α \ Int)],
i∈P bi ∧ i∈N ¬bi ∧ i∈P 1 αi ∧ i∈N 1 ¬αi 1 i∈P (s 1 i × s 2 i ) ∧ i∈N ¬(s 1 i × s 2 i ) Σ N ′ ⊆N Hp(s 1 N ′ × s 2 N ′ ) (s1 × s2) Hp(s1) * Hp(s2) i∈P (s 1 i → s 2 i ) ∧ i∈N ¬(s 1 i → s 2 i ) 1
where

(s 1 N ′ × s 2 N ′ ) = ( i∈P s 1 i ∧ i∈N ′ ¬s 1 i × i∈P s 2 i ∧ i∈N \N ′ ¬s 2 i ).
we can build the minimum one by taking the intersection of them. If we continue expanding t, any result type we obtain is an intersection of some of the result types we have deduced for p = 1. Indeed, assume we expand t so that we get p copies of t. Then we would have to solve either ( i=1..p αi → βi ≥ s) or ( i=1..p αi → βi ≥ s). For the first constraint to hold, by the decomposition rule of arrows, there exists i0 such that s ≤ αi 0 → βi 0 , which is the same constraint as for p = 1. The second constraint implies s ≤ αi → βi for all i; we recognize again the same constraint as for p = 1 (except that we intersect p copies of it). Consequently, expanding does not give us more information, and it is enough to take p = 1 as the heuristic number for this case. Following the discussion above, we propose in Table 1 a heuristic number Hp(s) that, according to the shape of s, sets an upper bound to the number of copies of t. We assume that s is in normal form. This definition can be easily extended to recursive types by memoization.

The next example shows that performing the expansion of t with Hp(s) copies may not be enough to get a result type, confirming that this number is a heuristic that does not ensure completeness. Let t = ((true

× (Int → α)) → t1) ∧ ((false × (α → Bool)) → t2) s = (Bool × (Int → Bool)) (27)
Here dom(t) is (true×(Int → α))∨(false×(α → Bool)). The type s cannot be completely contained in either summand of dom(t), but it can be contained in dom(t). Indeed, the first summand requires the substitution of α to be a supertype of Bool while the second one requires it to be a subtype of Int. As Bool is not a subtype of Int, to make the application possible, we have to expand the function type at least once. However, according to Table 1, the heuristic number in this case is 1 (ie, no expansions).

Expansion of s.

For simplicity, we assume that dom( i∈I tσi) = i∈I dom(t)σi, so that the tallying problem for the application becomes j∈J sσ ′ j ≤ i∈I dom(t)σi. We now give some heuristic numbers for |J| depending on dom(t).

First, consider the following example where dom(t) is a union:

dom(t) = (Int → ((Bool → Bool) ∧ (Int → Int))) ∨(Bool → ((Bool → Bool) ∧ (Int → Int) ∧ (Real → Real))) s = (Int → (α → α)) ∨ (Bool → (β → β)) (28)
For the application to succeed, we need to expand Int → (α → α) with two copies (so that we can make two distinct instantiations α = Bool and α = Int) and Bool → (β → β) with three copies (for three instantiations β = Bool, β = Int, and β = Real), corresponding to the first and the second summand in dom(t) respectively. Since the expansion distributes the union over the intersections, we need to get six copies of s. In detail, we need the following six substitutions: {α = Bool, β = Bool}, {α = Bool, β = Int}, {α = Bool, β = Real}, {α = Int, β = Bool}, {α = Int, β = Int}, and {α = Int, β = Real}, which are the Cartesian products of the substitutions for α and β.

If dom(t) is an intersection of basic types, we use 1 for the heuristic number. If it is an intersection of product types, we can rewrite it as a union of products and we only need to consider the case of just a single product type. For instance,

dom(t) = ((Int → Int) × (Bool → Bool)) s = ((α → α) × (α → α)) (29)
It is easy to infer that the substitution required by the left component needs α to be Int, while the one required by the right component needs α to be Bool. Thus, we need to expand s at least once. Assume that s = (s1 × s2) and we need qi copies of si with the type substitutions: σ i 1 , . . . , σ i q i . Generally, we can expand the whole product type so that we get s1 × s2 copies as follows:

j=1..q 1 (s1 × s2)σ 1 j ∧ j=1..q 2 (s1 × s2)σ 2 j = (( j=1..q 1 s1σ 1 j ∧ j=1..q 2 s1σ 2 j ) × ( j=1..q 1 s2σ 1 j ∧ j=1..q 2 s2σ 2 j )) Clearly, this expansion type is a subtype of ( j=1..q 1 s1σ 1 j × j=1..q 2 s2σ 2 j ) and so the type tallying succeeds.

Next, consider the case where dom(t) is an intersection of arrows: where

dom(t) = (Int → Int) ∧ (Bool → Bool) s = α → α (30)
(t 1 N ′ × t 2 N ′ ) = ( i∈P t 1 i ∧ i∈N ′ ¬t 1 i × i∈P t 2 i ∧ i∈N \N ′ ¬t 2 i ),
Without expansion, we need (α → α) ≤ (Int → Int) and (α → α) ≤ (Bool → Bool), which reduce to α = Int and α = Bool; this is impossible. Thus, we have to expand s once, for the two conjunctions in dom(t).

Note that we may also have to expand s because of unions or intersections occurring under arrows. For example, dom(t) = t ′ → ((Int → Int) ∧ (Bool → Bool))

s = t ′ → (α → α) (31)
As in Example (30), expanding once the type α → α (which is under an arrow in s) makes type tallying succeed. Because (t ′ → s1) ∧ (t ′ → s2) ≃ t ′ → (s1 ∧ s2), we can in fact perform the expansion on s and then use subsumption to obtain the desired result. Likewise, we may have to expand s if dom(t) is an arrow type and contains an union in its domain. Therefore, we have to look into dom(t) and s deeply if they contain both arrow types. Following these intuitions, we define in Table 2 a heuristic number Hq(dom(t)) that, according to the sharp of dom(t), sets an upper bound to the number of copies of s.

Together. Up to now, we have considered the expansions of t and s separately. However, it might be the case that the expansions of t and s are interdependent, namely, the expansion of t causes the expansion of s and vice versa. Here we informally discuss the relationship between the two, and hint as why decidability is difficult to prove.

Let dom(t) = t1 ∨ t2, s = s1 ∨ s2, and suppose the type tallying between dom(t) and s requires that tiσi ≥ si, where σ1 and σ2 are two conflicting type substitutions. Then we can simply expand dom(t) with σ1 and σ2, yielding t1σ1 ∨ t2σ1 ∨ t1σ2 ∨ t2σ2. Clearly, this expansion type is a supertype of t1σ1 ∨ t2σ2 and thus a supertype of s. Note that as t is on the bigger side of ≤, then the extra chunk of type brought by the expansion (i.e., t2σ1 ∨ t1σ2) does not matter. That is to say, the expansion of t would not cause the expansion of s.

However, the expansion of s could cause the expansion of t, and even a further expansion of s itself. Assume that s = s1 ∨ s2 and si requires a different substitution σi (i.e., siσi ≤ dom(t) and σ1 is in conflict with σ2). If we expand s with σ1 and σ2, then we have (s1 ∨ s2)σ1 ∧ (s1 ∨ s2)σ2 = (s1σ1 ∧ s1σ2) ∨ (s1σ1 ∧ s2σ2) ∨ (s2σ1 ∧ s1σ2) ∨ (s2σ1 ∧ s2σ2) It is clear that s1σ1 ∧ s1σ2, s1σ1 ∧ s2σ2 and s2σ1 ∧ s2σ2 are subtypes of dom(t). Consider the extra type s1σ2 ∧ s2σ1. If this extra type is empty (e.g., because s1 and s2 have different top-level constructors), or if it is a subtype of dom(t), then the type tallying succeeds. Otherwise, in some sense, we need to solve another type tallying between s ∧ (s2σ1 ∧ s1σ2) and dom(t), which would cause the expansion of t or s. This is the main reason why we fail to prove the decidability of the application problem (that is, deciding •∆) so far.

To illustrate this phenomenon, consider the following example:

dom(t) = ((Bool → Bool) → (Int → Int)) ∨((Bool → Bool) ∨ (Int → Int)) → ((β → β) ∨ (Bool → Bool)) ∨(β × β) s = (α → (Int → Int)) ∨ ((Bool → Bool) → α) ∨ (Bool × Bool) (32)
Let us consider each summand in s respectively. A solution for the first summand is α ≥ Bool → Bool, which corresponds to the first summand in dom(t). The second one requires α ≤ Int → Int and the third one β ≥ Bool. Since (Bool → Bool) is not subtype of (Int → Int), we need to expand s once, that is, Therefore, we need to consider another type tallying involving this extra type and dom(t). By doing so, we obtain β = Int; however we have inferred before that β should be a supertype of Bool. Consequently, we need to expand dom(t); the expansion of dom(t) with { Bool / β } and { Int / β } makes the type tallying succeed.

s ′ = s{ Bool → Bool / α } ∧ s{ Int → Int
In day-to-day examples, the extra type brought by the expansion of s is always a subtype of (the expansion type of) dom(t), and we do not have to expand dom(t) or s again. The heuristic numbers we gave seem to be enough in practice.

Figure 12. Explicit Inference system for type-substitutions

The translation from the language in (33) to the language in (34) is given contextually to the typing relation. In particular we extend the typing rules in order to prove judgments of the form ∆, Γ ⊢ I a : t ⊲ e where a is a term of the source language (33) and e its translation in the intermediate language (34).

The type inference rules that perform the translation from (33) to the language in (34) are specified in Figure 12. The rules (INF-VAR-*) translate variables into polymorphic or monomorphic ones according to whether their type contains polymorphic type variables or not. The rule for application, (INF-APPL) simply applies the sets of type-substitutions inferred for the function and for its argument to them. The rule for match (INF-MATCH) is the standard CDuce rule (see [START_REF] Frisch | Théorie, conception et réalisation d'un langage de programmation fonctionnel adapté à XML[END_REF]) except that it stores in Ξj the type variables occurring in the types of each capture variable of pj. The rule (INT-ABSTR) is standard too, except that it merges the different Ξ's and σ's found for the same branch while checking the type for different arrows of the interface. Notice that these last two rules use the standard CDuce meta-operator " " to compute the type environment for pattern's capture variables (see [START_REF] Frisch | Théorie, conception et réalisation d'un langage de programmation fonctionnel adapté à XML[END_REF]). Formally, let t and p be a type and a parameter such that t ≤ p . We define (t p)(x) = {(v/p)(x) | v ∈ t}, that is:

t x = {x → t} t t0 = {} t (p1&p2) = π1(t) p1 ∪ π2(t) p2 (t (p1, p2))(x) =    (π1(t) p1)(x) if x ∈ var(p1) \ var(p2) (π2(t) p2)(x)
if x ∈ var(p2) \ var(p1)

(t 1 ,t 2 )∈π(t) ((t1 p1)(x), (t2 p2)(x)) if x ∈ var(p2) ∩ var(p1) t p1|p2 = (t ∧ p1 ) p1 ∪ (t \ p1 ) p2 t (x := c) = {x → bc} if t ≤ 0 {} otherwise where the pairwise union of mappings assumes that the domains are distinct

(Γ1 ∪ Γ2)(x) = Γ1(x) if x ∈ dom(Γ1) Γ2(x) if x ∈ dom(Γ2)
Finally, the compilation of the explicitly-typed language (34) into the intermediate language (35) is given by the following rules: These rules are mostly straightforward except that we try to compile into monomorphic expression variables as many capture variables as possible. In particular, we compile as monomorphic also those polymorphic expression variables for which we can statically determine that type substitutions will have no effect at run-time (ie, every variable x for which Ξ(x) ∩ dom(Σ) = ∅ holds).

x Σ,Ξ = x x Σ,Ξ = x if Ξ(

E.3 Evaluation Rules

The evaluation procedure transforms the evaluation language into values of the following form :

v ::= c | (v, v) | (v, v)Σ | λ s Σ p.e,
x, E Notice that closures now include a slot for a variable. This slot stores the fresh variables that were introduced in the translations of lambdas and it is used at the application (rule (OE-APPLY).

The operational semantics must be modified to take into account new constructions and to lazily propagate type substitutions for all constructed values. where the ⊕ operator has the following definition (γ ranges over value substitutions, ie mappings from expression variables to values):

(γ1 ⊕ γ2)(x) =    γ1(x) if x ∈ dom(γ1) \ dom(γ2) γ2(x)
if x ∈ dom(γ2) \ dom(γ1) (γ1(x), γ2(x)) if x ∈ dom(γ1) ∩ dom(γ2)

Notice that in the fourth rule of the definition of pattern matching when we deconstruct a pair that is annotated by a lazy type-substitution we do not immediately propagate the substitution to the subcomponents. Instead we delay it until this substitution is needed. This is implemented by the "delay substitution" operation "@" defined as

(v@Σ) =     
c@Σ = c λ t Σ ′ p.e, x, E @Σ = λ t comp(Σ,Σ ′ ) p.e, x, E (v1, v2)@Σ = (v1, v2)Σ (v1, v2) Σ ′ @Σ = (v1, v2) comp(Σ,Σ ′ ) This requires a modification of the rules used to check the type of a value: c ∈o t ⇔ bc ≤ t λ s Σ p.e, x, E ∈o t ⇔ s ≤ t λs Σ p.e, x, E ∈o t ⇔ s(eval(E , Σ)) ≤ t (v1, v2) ∈o t ⇔ vi ∈o πi(t), i ∈ 1, 2 (v1, v2)Σ ∈o t ⇔ vi@Σ ∈o πi(t), i ∈ 1, 2 where, we recall, the evaluation of the symbolic set of type-substitutions is inductively defined as eval(E , σI ) = σI eval(E , comp(Σ, Σ ′ )) = eval(E , Σ) • eval(E , Σ ′ ) eval(E , sel(x, i∈I ti→si, Σ)) = [ σj ∈ eval(E , Σ) | ∃i∈I : E (x) ∈o tiσj ]

F. Experiments

To gauge the practicality of our local type inference algorithm, we performed extensive experiments, applying higher-order polymorphic function. To that end, we automatically generated function applications from the List module of the OCaml standard distribution. More specifically we considered the following functions: We then devised a series of tests as follows. First, we generated all the applications that were well typed in OCaml from one function against all the others. This gave, for instance, applications such as "map length" or "map hd", that is performing local type inference for the applications

(α→β)→[α]→[β] •_ α→Int and (α→β)→[α]→[β] •_ [α]
→α Then, for each function f of type t and f1, . . . , fn of type t1, . . . , tn such that all the applications "f f1", . . . , "f fn" are well-typed, we performed the local type inference on t •_ t1∧ . . . ∧t k for all k ≤ n Remark that these applications are well typed since a function of type t1∧ . . . ∧tn has also type ti (i = 1..n), and any of these type is in the domain of t (since each individual application tti is welltyped. Notice also that intersection of arrow types are never empty (all arrow types contain the type 1 → 0. Conversely, for all triple of functions f , f1, f2 such as "f1f " and "f2f " are well-typed, we also typed performed local type inference for t1∨t2 •_ t.

Lastly, we added to our test suite some ill-typed applications (such as (α→β)→[α]→[β]•_Int) to ensure our implementation indeed detects these as invalid applications. Our test machine is an average laptop with 64bit Intel Core i3-2367M, 1.4Ghz, 4 cores and 8GB of RAM.

The results of our experiments are summarized in the following As expected, the behavior of our algorithm is exponential (subtyping is already EXPTIME-complete, although our implementation performs very well even for large types). We illustrate the general behavior of our algorithm on two kinds of application. First, given a function of type t → s where t does not contain any arrows (but may contain products, sequences and so forth), local type inference scales linearly with the sum of the size of types t → s and u, when computing (t → s) •_ u. While these tests already represent cases that are unlikely to happen in practice (the worst time case features more than 45 connectives/constructors, namely 15 intersections and 30 arrows), we conjecture that standard optimization techniques (hash-consing, memoization, laziness) will make our semi-naïve implementation even more tractable. During the experiment, memory usage was negligible (few megabytes).

Finally we also tested the type inference for applications of curried functions to several arguements. We added (by hand) to our test suite a set of functions that accept up to n arguments. More precisely for each arity n we added functions with the following types

α1 → • • • → αn → Int α1 → • • • → αn → α1 α1 → • • • → αn → (α1 × . . . × αn) (β1 → α1) → • • • → (βn → αn) → Int (β1 → α1) → • • • → (βn → αn) → α1 (β1 → α1) → • • • → (βn → αn) → (α1 × . . . × αn)
each of these functions, if its arity is k, was then applied to k other randomly selected functions of this set. The test showed that our implementation can smoothly handle inference for the application of up to 20 arguments (for n = 20 the 120 tests take less than one second of cpu on a desktop workstation), then the exponential blowup becomes too important (in particular because of the memory footprint). The following Consider that in the standard library of OCaml export all functions have at most 5 arguments, and that there is margin for important improvement since we did not simplify the types of partial applications (whose intersection types are in general quite redundant). Our implementation is already included in the development branch of the the CDuce distribution which can be retrieved at https://www.cduce.org/redmine/projects/cduce. It currently is in alpha-testing therefore we recommend the user to check the bug-tracker for open issues. Also available is a prototype which implements the work described in both papers: type inference/reconstruction for implicitly-typed expressions, constraint solving with basic simplification algorithms, evaluation. The implementation is naive, not optimized, and implements very naive simplification heuristics, but it permits a smoother and friendlier evaluation and testing of our system since it is stable, includes an interactive toplevel and contains, a different test suite based on the examples used in both papers. It is available at http://www.pps.univ-paris-diderot.fr/~gc/misc/polyduce.tar.gz

Definition 2 . 2 (

 22 Expressions). Expressions are the terms inductively generated by the following grammar e ::= c | x | ee | λ ∧ i∈I s i →t i x.e | e∈t ? e : e

Figure 4 .

 4 Figure 4. Type reconstruction rules

  type RBtree(α) = Btree(α) | Rtree(α) (* Black rooted RB tree: *) type Btree(α) = [] | <black elem=α>[ RBtree(α) RBtree(α) ] (* Red rooted RB tree: *) type Rtree(α) = <red elem=α>[ Btree(α) Btree(α) ] type Wrongtree(α) = <red elem=α>( [ Rtree(α) Btree(α) ] | [ Btree(α) Rtree(α) ]) type Unbalanced(α) = <black elem=α>( [ Wrongtree(α) RBtree(α) ] | [ RBtree(α) Wrongtree(α) ]) let balance ( Unbalanced(α) -> Rtree(α) ; β\Unbalanced(α) -> β\Unbalanced(α) ) | (<black (z)>[ <red (y)>[ <red (x)>[ a b ] c ] d ] | <black (z)>[ <red (x)>[ a <red (y)>[ b c ] ] d ] | <black (x)>[ a <red (z)>[ <red (y)>[ b c ] d ] ] | <black (x)>[ a <red (y)>[ b <red (z)>[ c d ] ] ] ) & Unbalanced(α) -> <red (y)>[ <black (x)>[ a b ] <black (z)>[ c d ] ] | x -> x let insert (x : α) (t : Btree(α)) : Btree(α) = let ins_aux ( [] -> Rtree(α); Btree(α)\[] -> RBtree(α)\[]; Rtree(α) -> Rtree(α)|Wrongtree(α) ) | [] -> <red elem=x>[ [] [] ] | (<(color) elem=y>[ a b ]) & z -> if x << y then balance <(color) elem=y>[ (ins_aux a) b ] else if x >> y then balance <(color) elem=y>[ a (ins_aux b) ] else z in match ins_aux t with | <_ (y)>[ a b ] -> <black (y)>[ a b ]

  RBtree = Btree | Rtree type Btree = [] | <black elem=Int>[ RBtree RBtree ] type Rtree = <red elem=Int>[ Btree Btree ];; type Wrongtree = Wrongleft | Wrongright type Wrongleft = <red elem=Int>[ Rtree Btree ] type Wrongright = <red elem=Int>[ Btree Rtree ] type Unbalanced = <black elem=Int>([ Wrongtree RBtree ] | [ RBtree Wrongtree ]);; let balance ( Unbalanced -> Rtree ; Rtree -> Rtree ; Btree\[] -> Btree\[] ;

  y then balance <(color) elem=y>[ (ins_aux a) b ] else if x >> y then balance <(color) elem=y>[ a (ins_aux b) ] else z in match ins_aux t with | <_ (y)>[ a b ] -> <black (y)>[ a b ] which, besides being monomorphic, requires the introduction of several intermediate types (in particular

type

  UTree = <black (Any)>[ <red (Any)>[ <red (Any)>[ Any Any ] Any ] Any ] | <black (Any)>[ <red (Any)>[ Any <red (Any)>[ Any Any ] ] Any ] | <black (Any)>[ Any <red (Any)>[ <red (Any)>[ Any Any ] Any ] ] | <black (Any)>[ Any <red (Any)>[ Any <red (Any)>[ Any Any ] ] ]

type

  Envelope(α, β) = <Envelope>[ Header(β)? Body(α) ] type Header(β) = <Header> β type Body(α) = <Body> α We define an enrich function which maps functions into a function with the same typing pattern as even (NOTE: in the current development version of CDuce this function cannot be executed because neither the :: notation, nor monomorphic varibles in patterns are implemented, yet). (* enrich envelope headers with info computed by applying *) (* the argument function f to the body of the envelope *) enrich :: ( α -> β ) -> ( ( Envelope(α, β) -> <Envelope>[Header(β) Body(α)] ) & ( γ\Envelope(α, β) -> γ\Envelope(α, β) ) ) enrich f x = match x with | (<Envelope>[ <Body> b ]) & Envelope(α, β) -> <Envelope> [ <Header>(f b) <Body>(enrich f b) ] | (<Envelope>[ <Header> h <Body> b ]) & Envelope(α, β) -> <Envelope> [ <Header>((f b)@h) <Body>(enrich f b) ] | lst & [ (AnyXML\Envelope(α, β)|Char)* ] -> (map lst with y -> enrich f y) | <(x)>y -> <(x)>(enrich f y) | y -> y

  [(AnyXml|Char)*]: type Envelope = <Envelope>[ Header? Body ] type Header = <Header> B type Body = <Body> A type A = [(AnyXml|Char)*] type B = [(AnyXml|Char)*] let enrich (f: A -> B): ( (Envelope -> <Envelope>[ Header Body ]) & (A -> A) & (Char -> Char) & (AnyXml -> AnyXml)) = (fun ( Envelope -> <Envelope>[ Header Body ] ; A -> A ; Char -> Char ; AnyXml -> AnyXml) | <Envelope>[ <Body> b ] -> <Envelope> [ <Header>(f b) <Body>(enrich f b) ] | <Envelope>[ <Header> h <Body> b ] -> <Envelope> [ <Header>((f b)@h) <Body>(enrich f b) ] | lst & [ (AnyXml|Char)* ] -> (map lst with y -> enrich f y) | <(x)>y -> <(x)> (enrich f y) | y -> y);;

e

  ::= c | x | (e, e) | πi(e) | e e | λ ∧ i∈I t i →s i x.e | e∈t ? e : e | e[σj]j∈J .

  [σi]i∈I , [σj]j∈J two sets of type substitutions. Then ∆ ; Γ ⊢ A (e[σi]i∈I )[σj]j∈J : t ⇐⇒ ∆ ; Γ ⊢ A e([σj]j∈J • [σi]i∈I ) : t Proof. ⇒: consider the following derivation: . . . ∆ ; Γ ⊢ A e : s σi ♯ ∆ ∆ ; Γ ⊢ A e[σi]i∈I : i∈I sσi σj ♯ ∆ ∆ ; Γ ⊢ A (e[σi]i∈I )[σj]j∈J : j∈J ( i∈I sσi)σj As σi ♯ ∆, σj ♯ ∆ and dom(σj • σi) = dom(σi) ∪ dom(σj), we have σj • σi ♯ ∆. Then by (ALG-INST), we have ∆ ; Γ ⊢ A e([σj • σi]j∈J,i∈I ) : j∈J,i∈I s(σj • σi), that is ∆ ; Γ ⊢ A e([σj]j∈J • [σi]i∈I ) : j∈J ( i∈I sσi)σj. ⇐: consider the following derivation: . . . ∆ ; Γ ⊢ A e : s σj • σi ♯ ∆ ∆ ; Γ ⊢ A e([σj]j∈J • [σi]i∈I ) : j∈J,i∈I s(σj • σi) As σj • σi ♯ ∆ and dom(σj • σi) = dom(σi) ∪ dom(σj), we have σi ♯ ∆ and σj ♯ ∆. Then applying the rule (ALG-INST) twice, we have ∆ ; Γ ⊢ A (e[σi]i∈I )[σj]j∈J : j∈J ( i∈I sσi)σj, that is ∆ ; Γ ⊢ A (e[σi]i∈I )[σj]j∈J : j∈J,i∈I s(σj • σi).

Lemma B. 10 .′ 2 :

 102 Let e, e ′ ∈ E0 be two expressions. If erase(e) = erase(e ′ ), then e ⊓ e ′ exists and erase(e ⊓ e ′ ) = erase(e) = erase(e ′ ). Proof. By induction on the structures of e and e ′ . Because erase(e) = erase(e ′ ), the two expressions have the same structure up to their sets of type substitutions. c, c: straightforward. x, x: straightforward. (e1, e2), (e ′ 1 , e ′ 2 ): we have erase(ei) = erase(e ′ i ). By induction, ei ⊓ e ′ i exists and erase(ei ⊓ e ′ i ) = erase(ei) = erase(e ′ i ). Therefore (e1, e2) ⊓ (e ′ 1 , e ′ 2 ) exists and erase((e1, e2) ⊓ (e ′ 1 , e ′ 2 )) = erase(((e1 ⊓ e ′ 1 ), (e2 ⊓ e ′ 2 ))) = (erase(e1 ⊓ e ′ 1 ), erase(e2 ⊓ e ′ 2 )) = (erase(e1), erase(e2)) = erase((e1, e2)) Similarly, we also have erase((e1, e2) ⊓ (e ′ 1 , e ′ 2 )) = erase((e ′ 1 , e ′ 2 )). πi(e), πi(e ′ ): we have erase(e) = erase(e ′ ). By induction, e ⊓ e ′ exists and erase(e ⊓ e ′ ) = erase(e) = erase(e ′ ). Therefore πi(e) ⊓ πi(e ′ ) exists and erase(πi(e) ⊓ πi(e ′ )) = erase(πi(e ⊓ e ′ )) = πi(erase(e ⊓ e ′ )) = πi(erase(e)) = erase(πi(e)) Similarly, we also have erase(πi(e) ⊓ πi(e ′ )) = erase(πi(e ′ )). e1e2, e ′ 1 e we have erase(ei) = erase(e ′ i ). By induction, ei ⊓ e ′ i exists and erase(ei

  j∈J ′ : we have erase(e) = erase(e ′ ). By induction, e ⊓ e ′ exists and erase(e ⊓ e ′ ) = erase(e) = erase(e ′ ). Therefore (e[σj]j∈J ) ⊓ (e ′ [σj] j∈J ′ ) exists and erase((e[σj]j∈J ) ⊓ (e ′ [σj] j∈J ′ )) = erase((e ⊓ e ′ )[σj] j∈J∪J ′ ) = erase(e ⊓ e ′ ) = erase(e) = erase(e[σj]j∈J ) Similarly, we also have erase((e[σj]j∈J ) ⊓ (e ′ [σj] j∈J ′ )) = erase(e ′ [σj] j∈J ′ ). e, e ′ [σj] j∈J ′ : a special case of e[σj]j∈J and e ′ [σj] j∈J ′ where [σj]j∈J = [σ id ]. e[σj]j∈J , e ′ : a special case of e[σj]j∈J and e ′ [σj] j∈J ′ where [σj] j∈J ′ = [σ id ]. Lemma B.11. Let e, e ′ ∈ E0 be two expressions. If erase(e) = erase(e ′ ), ∆ ; Γ ⊢ e : t, ∆ ′ ; Γ ′ ⊢ e ′ : t ′ , e ♯ ∆ ′ and e ′ ♯ ∆, then ∆ ; Γ ⊢ e ⊓ e ′ : t and ∆ ′ ; Γ ′ ⊢ e ⊓ e ′ : t ′ .

(

  const): ∆ ; Γ ⊢ c : bc. As erase(e ′ ) = c, e ′ is either c or c[σj]j∈J . If e ′ = c, then e ⊓ e ′ = c, and the result follows straightforwardly. Otherwise, we have e ⊓ e ′ = c[σ id , σj]j∈J . Since e ′ ♯ ∆, we have σj ♯ ∆. By (instinter), we have ∆ ; Γ ⊢ c[σ id , σj]j∈J : bc ∧ j∈J bcσj, that is, ∆ ; Γ ⊢ c[σ id , σj]j∈J : bc. (var): Γ ⊢ x : Γ(x). As erase(e ′ ) = x, e ′ is either x or x[σj]j∈J . If e ′ = x, then e ⊓ e ′ = x, and the result follows straightforwardly. Otherwise, we have e ⊓ e ′ = x[σ id , σj]j∈J . Since e ′ ♯ ∆, we have σj ♯ ∆. By (instinter), we have ∆ ; Γ ⊢ x[σ id , σj]j∈J : Γ(x)∧ j∈J Γ(x)σj, that is, ∆ ; Γ ⊢ x[σ id , σj]j∈J : Γ(x). (pair): consider the following derivation:

(

  INF-CONST): straightforward (take e as c). (INF-VAR): straightforward (take e as x). (INF-PAIR): consider the derivation . . . ∆ ; Γ ⊢ I a1 : t1 . . . ∆ ; Γ ⊢ I a2 : t2 ∆ ; Γ ⊢ I (a1, a2) : t1 × t2 Applying the induction hypothesis, there exists an expression ei such that erase(ei) = ai and ∆ ; Γ ⊢ A ei : ti. Then by (ALG-PAIR), we have ∆ ; Γ ⊢ A (e1, e2) : t1 × t2. Moreover, according to Definition B.2, we have erase((e1, e2)) = (erase(e1), erase(e2)) = (a1, a2). (INF-PROJ): consider the derivation . . . ∆ ; Γ ⊢ I a : t u ∈ ∐ i ∆ (t) ∆ ; Γ ⊢ I πi(a) : u By induction, there exists an expression e such that erase(e) = a and ∆ ; Γ ⊢ A e : t. Let u = π π πi( i∈I tσi). As σi ♯ ∆, by (ALG-INST), we have ∆ ; Γ ⊢ A e[σi]i∈I : i∈I tσi. Moreover, since i∈I tσi ≤ 1 × 1, by (ALG-PROJ), we get ∆ ; Γ ⊢ A πi(e[σi]i∈I ) : π π πi( i∈I tσi). Finally, according to Definition B.2, we have erase(πi(e[σi]i∈I )) = πi(erase(e[σi]i∈I )) = πi(erase(e)) = πi(a). (INF-APPL): consider the derivation . . . ∆ ; Γ ⊢ I a1 : t . . . ∆ ; Γ ⊢ I a2 : s u ∈ t •∆ s ∆ ; Γ ⊢ I a1a2 : u By induction, we have that (i) there exists an expression e1 such that erase(e1) = a1 and ∆ ; Γ ⊢ A e1 : t and (ii) there exists an expression e2 such that erase(e2) = a2 and ∆ ; Γ ⊢ A e2 : s. Let u = ( i∈I tσi) • ( j∈J sσj). As σ h ♯ ∆ for h ∈ I ∪ J, applying (ALG-INST), we get ∆ ; Γ ⊢ A e1[σi]i∈I : i∈I tσi and ∆ ; Γ ⊢ A e2[σj]j∈J : j∈J sσj. Then by (ALG-APPL), we have ∆ ; Γ ⊢ A (e1[σi]i∈I )(e2[σj]j∈J ) : ( i∈I tσi)•( j∈J sσj). Furthermore, according to Definition B.2, we have erase((e1[σi]i∈I )(e2[σj]j∈J )) = erase(e1)erase(e2) = a1a2. (INF-ABSTR): consider the derivation ∀i ∈ I. . . . ∆ ∪ var( i∈I ti → si) ; Γ, (x : ti) ⊢ I a : s

  (INF-CASE-NONE): consider the derivation . . . ∆ ; Γ ⊢ I a : t ′ t ′ ⊑∆ 0 ∆ ; Γ ⊢ I (a∈t ? a1 : a2) : 0 By induction, there exists an expression e such that erase(e) = a and ∆ ; Γ ⊢ A e : t ′ . Let [σi]i∈I t ′ ⊑∆ 0. Since σi ♯ ∆, by (ALG-INST), we have ∆ ; Γ ⊢ A e[σi]i∈I : i∈I t ′ σi. Let e1 and e2 be two expressions such that erase(e1) = a1 and erase(e2) = a2. Then we have erase((e[σi]i∈I )∈t ? e1 : e2) = (a∈t ? a1 : a2). Moreover, since i∈I t ′ σi ≤ 0, by (ALG-CASE-NONE), we have ∆ ; Γ ⊢ A ((e[σi]i∈I )∈t ? e1 : e2) : 0.

Definition C. 4 .

 4 sσ holds and ∀(t, ≥, s) ∈ C . sσ ≤ tσ holds. If σ is a solution to C, we write σ C. Given two sets of constraint-sets S1, S2 ⊆ P(C ), we define their union as S1 ⊔ S2 = S1 ∪ S2 and their intersection as

Definition C. 6 .

 6 Let ≤ be the subtyping relation induced by a well-founded convex model with infinite support ([_], D). We define the family (≤n) n∈N of subtyping relations as t ≤n s def ⇐⇒ ∀η. [t]nη ⊆ [s]nη where [_]n is the rank n interpretation of a type, defined as [t]nη = {d ∈ [t]η | height(d) ≤ n} and height(d) is the height of an element d in D, defined as height(c) = 1 height((d, d ′ )) = max(height(d), height(d ′ )) + 1 height({(d1, d ′ 1 ), . . . , (dn, d ′ n )}) = 1 n = 0 max(height(di), height(d ′ i ), . . .) + 1 n > 0 Lemma C.7. Let ≤ be the subtyping relation induced by a well-founded convex model with infinite support. Then(1) t ≤0 s for all t, s ∈ T .(2) t ≤ s ⇐⇒ ∀n. t ≤n s. (3) i∈I (ti × si) ≤n+1 j∈J (tj × sj) ⇐⇒ ∀J ′ ⊆ J .

6 .Definition C. 8 .( 1 )

 681 Given a constraint-set C and a type substitution σ, we define the rank n satisfaction predicate n as σ n C def ⇐⇒ ∀(t, ≤, s) ∈ C. t ≤n s and ∀(t, ≥, s) ∈ C. s ≤n t Lemma C.9. Let ≤ be the subtyping relation induced by a well-founded convex model with infinite support. Then (1) σ 0 C for all σ and C. (2) σ C ⇐⇒ ∀n. σ n C. Proof. Consequence of Lemma C.7. Given a set Σ of types, we write C(Σ) for the constraint-set {(t, ≤, 0) | t ∈ Σ}. Lemma C.10 (Soundness). Let C be a constraint-set. If ∅ ⊢ N C S , then for all normalized constraintset C ′ ∈ S and all substitution σ, we have σ C ′ ⇒ σ C. Proof. We prove the following stronger statements. Assume Σ ⊢ N C S . For all C ′ ∈ S , σ and n, if σ n C(Σ) and σ n C ′ , then σ n C. (2) Assume Σ ⊢ * N C S . For all C ′ ∈ S , σ and n, if σ n C(Σ) and σ n C ′ , then σ n+1 C.

  : according to Definition C.[START_REF] Castagna | Set-theoretic Foundation of Parametric Polymorphism and Subtyping[END_REF], if there exists Ci ∈ Si such that Ci = ∅, then i∈I Si = ∅, and the result follows immediately. Otherwise, we have C ′ = i∈I Ci, where Ci ∈ Si. As σ n C ′ , then clearly σ n Ci. By induction, we haveσ n {(ti ci t ′ i )}. Therefore, we get σ n {(ti ci t ′ i ) | i ∈ I}. (NSYM): by induction, we have σ n {(t ≤ t ′ )}. Then clearly σ n {(t ′ ≥ t)}.(NZERO): by induction, we have σ n {(t∧¬t ′ ≤ 0)}. According to set-theory, we have σ n {(t ≤ t ′ )}. (NDNF): similar to the case of (NZERO). (NUNION): similar to the case of (NZERO). (NTLV): assume α ′ has the smallest order in P ∪ N . If α ′ ∈ P , then we haveC ′ = (α ′ , ≤, ¬t α ′ ). From σ n C ′ , we deduce σ(α ′ ) ≤n ¬t α ′ σ.Intersecting both sides of the inequality by the same type, we obtain σ(α′ ) ∧ t α ′ σ ≤n 0, that is, σ n {( α∈P α ∧ α∈N ¬α ∧ τ0 ≤ 0)}. Otherwise,we have α ′ ∈ N and the result follows as well. (NHYP): since we have τ0 ∈ Σ and σ n C(Σ), then σ n {(τ0 ≤ 0)} holds. (NASSUM): if n = 0, then σ 0 {(τ0 ≤ 0)} holds. Suppose n > 0. From σ n C(Σ) and σ k C ′ , it is easy to prove that σ k C(Σ) (*) and σ k C ′ (**) hold for all 0 ≤ k ≤ n. We now prove that σ k {(τ0 ≤ 0}) (***) holds for all 1 ≤ k ≤ n. By definition of 0, we have σ 0 C(Σ ∪ {τ0}) and σ 0 C ′ . Consequently, by the induction hypothesis (item (2)), we have σ 1 {τ0 ≤ 0}. From this and (*), we deduce σ 1 C(Σ ∪ {τ0}). Because we also have σ 1 C ′ (by (**)), we can use the induction hypothesis (item (2)) again to deduce σ 2 {(τ0 ≤ 0}). Hence, we can prove (***) by induction on 1 ≤ k ≤ n. In particular, we have σ n {(τ0 ≤ 0}), which is the required result. (NBASIC): straightforward. (NPROD): If N ′ ⊆N (S 1 N ′ ⊔ S 2 N ′ ) is ∅, then the result follows straightforwardly. Otherwise, we have

  Otherwise, we have α ′ ∈ N and the result follows as well. (NHYP): it is clear that σ ∅. (NASSUM): as σ C(Σ) and σ {(τ0 ≤ 0)}, we have σ C(Σ ∪ {τ0}). By induction, the result follows. (NBASIC): straightforward. (NPROD): as

  σ

(Definition C. 16 .

 16 NEMPTY): it terminates immediately. (NJOIN): |C| decreases, and neither | \ Σ| nor U increase. (NSYM): U decreases and Σ is unchanged (NZERO): U decreases and Σ is unchanged. (NDNF): U decreases and Σ is unchanged. (NUNION): although |C| increases, U decreases and Σ is unchanged (NTLV): it terminates immediately. (NHYP): it terminates immediately. (NASSUM): as τ0 ∈ and τ0 / ∈ Σ, the number | \ Σ| decreases. (NBASIC): it terminates immediately. (NPROD): although (| \ Σ|, U, |C|) may not change, the next rule to apply must be one of (NEMPTY), (NJOIN), (NSYM), (NZERO), (NDNF), (NUNION), (NTLV), (NHYP) or (NASSUM). Therefore, either the normalization terminates or the triple decreases in the next step. (NARROW): similar to Case (NPROD). Lemma C.15 (Finiteness). Let C be a constraint-set and ∅ ⊢ N C S . Then S is finite. Proof. It is easy to prove that each normalizing rule generates a finite set of finite sets of normalized constraints. Let C be a normalized constraint-set and O an ordering on var(C). We say C is wellordered if for all normalized constraint (α, c, tα) ∈ C and for all β ∈ tlv(tα), O(α) < O(β) holds. Lemma C.17. Let C be a constraint-set and ∅ ⊢ N C S . Then for all normalized constraint-set C ′ ∈ S , C ′ is well-ordered.

  vp))ρi, ≤, ( j∈J sρj) → γ)} ∅ Therefore, we have ∅ ⊢ N {( i∈I τ k ρi, ≤, ( j∈J sρj) → γ)} ∅. So the result follows.

  ): consequence of Theorem C.51 and Lemma C.49. (2): consequence of Lemma C.53.

  ) It is clear that (20) ⊑ ∅ (21) and (21) ⊑ ∅

  / α } = ((Bool → Bool) → (Int → Int)) ∧ ((Int → Int) → (Int → Int)) ∨((Bool → Bool) → (Int → Int)) ∧ ((Bool → Bool) → (Int → Int)) ∨((Bool → Bool) → (Bool → Bool)) ∧ ((Int → Int) → (Int → Int)) ∨((Bool → Bool) → (Bool → Bool)) ∧ ((Bool → Bool) → (Int → Int)) ∨(Bool ×Bool) Almost all the summands of s ′ are contained in dom(t) except the extra type ((Bool → Bool) → (Bool → Bool)) ∧ ((Int → Int) → (Int → Int))

(

  e1, e2) Σ,Ξ = ( e1 Σ,Ξ , e2 Σ,Ξ ) e1e2 Σ,Ξ = e1 Σ,Ξ e2 Σ,Ξ eσI Σ,Ξ = e comp(Σ,σ I ),Ξ match e with p1:Ξ1→e1 | p2:Ξ2→e2 Σ,Ξ = match e Σ,Ξ with p1 → e1 Σ,(Ξ∪Ξ 1 ) | p2 → e2 Σ,(Ξ∪Ξ 2 )

(

  OE-CONST) E ⊢o c ⇓ c (OE-CLOSURE) E ⊢o λ t Σ x&p.e ⇓ λ t Σ p.e, x, E (OE-PAIRVALUE)E ⊢o (v1, v2) ⇓ (v1, v2)(OE-VAR) E ⊢o x ⇓ E (x) (OE-PVAR-C) E (x) = c E ⊢o xΣ ⇓ c (OE-PVAR-F) E (x) = λ t Σ ′ x ′ &p.e E ⊢o xΣ ⇓ λ t comp(Σ,Σ ′ ) p.e, x ′ , E (OE-PVAR-P) E (x) = (v1, v2) E ⊢o xΣ ⇓ (v1, v2)Σ (OE-PAIR) E ⊢o e1 ⇓ v1 E ⊢o e2 ⇓ v2 E ⊢o (e1, e2) ⇓ (v1, v2) (OE-APPLY) E ⊢o e1 ⇓ λ t Σ p.e, x, E ′ E ⊢o e2 ⇓ v0 E ′ , x → v0 ⊢o e ⇓ v E ⊢o e1e2 ⇓ v (OE-MATCH 1) E ⊢o e ⇓ v ′ v ′ /p1 = Ω E , v ′ /p1 ⊢o e1 ⇓ v E ⊢o match e with p1 → e1 | p2 → e2 ⇓ v (OE-MATCH 2) E ⊢o e ⇓ v ′ v ′ /p1 = Ω v ′ /p2 = Ω E , v ′ /p2 ⊢o e2 ⇓ v E ⊢o match e with p1 → e1 | p2 → e2 ⇓ v Pattern matching is defined as follows v/x = {x → v} v/t = {} if v ∈o t Ω otherwise (v1, v2)/(p1, p2) = v1/p1 ⊕ v2/p2 (v1, v2)Σ/(p1, p2) = v1@Σ/p1 ⊕ v2@Σ/p2 v/p1&p2 = v/p1 ⊕ v/p2 v/p1|p2 = v/p1 if v/p1 = Ω v/p2 otherwise v/(x := c) = {x → c}16 or Σ = i which is a special case of the condition (since dom(i) = ∅) that can be checked more easily.

1

  val length : 'a list -> int 2 val hd : 'a list -> 'a 3 val tl : 'a list -> 'a list 4 val nth : 'a list -> int -> 'a 5 val rev : 'a list -> 'a list 6 val append : 'a list -> 'a list -> 'a list 7 val rev_append : 'a list -> 'a list -> 'a list 8 val concat : 'a list list -> 'a list 9 val flatten : 'a list list -> 'a list 10 val iter : ('a -> unit) -> 'a list -> unit 11 val iteri : (int -> 'a -> unit) -> 'a list -> unit 12 val map : ('a -> 'b) -> 'a list -> 'b list 13 val mapi : (int -> 'a -> 'b) -> 'a list -> 'b list14val rev_map : ('a -> 'b) -> 'a list -> 'b list 15 val fold_left : ('a -> 'b -> 'a) -> 'a -> 'b list -> 'a 16 val fold_right : ('a -> 'b -> 'b) -> 'a list -> 'b -> 'b 17 val iter2 : ('a -> 'b -> unit) -> 'a list -> 'b list -> unit 18 val map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list 19 val rev_map2 : ('a -> 'b -> 'c) -> 'a list -> 'b list -> 'c list 20 val fold_left2 : ('a -> 'b -> 'c -> 'a) -> 'a -> 'b list -> 'c list -> 'a 21 val fold_right2 : ('a -> 'b -> 'c -> 'c) -> 'a list -> 'b list -> 'c -> 'c22 val for_all : ('a -> bool) -> 'a list -> bool 23 val exists : ('a -> bool) -> 'a list -> bool 24 val for_all2 : ('a -> 'b -> bool) -> 'a list -> 'b list -> bool 25 val exists2 : ('a -> 'b -> bool) -> 'a list -> 'b list -> bool 26 val mem : 'a -> 'a list -> bool 27 val memq : 'a -> 'a list -> bool 28 val find : ('a -> bool) -> 'a list -> 'a 29 val filter : ('a -> bool) -> 'a list -> 'a list 30 val find_all : ('a -> bool) -> 'a list -> 'a list 31 val partition : ('a -> bool) -> 'a list -> 'a list * 'a list 32 val assoc : 'a -> ('a * 'b) list -> 'b 33 val assq : 'a -> ('a * 'b) list -> 'b 34 val mem_assoc : 'a -> ('a * 'b) list -> bool val mem_assq : 'a -> ('a * 'b) list -> bool 36 val remove_assoc : 'a -> ('a * 'b) list -> ('a * 'b) list 37 val remove_assq : 'a -> ('a * 'b) list -> ('a * 'b) list 38 val split : ('a * 'b) list -> 'a list * 'b list 39 val combine : 'a list -> 'b list -> ('a * 'b) list 40 val sort : ('a -> 'a -> int) -> 'a list -> 'a list 41 val stable_sort : ('a -> 'a -> int) -> 'a list -> 'a list 42 val fast_sort : ('a -> 'a -> int) -> 'a list -> 'a list 43 val merge : ('a -> 'a -> int) -> 'a list -> 'a list -> 'a list

  type inference in ms However (and as expected) if we consider types t → s where t contains one, two, or more arrows, then local type inference becomes exponential with respect to the size of the argument u

  t = p∈P tp ∧ n∈N ¬tn ∧ q∈P ′ αq ∧ r∈N ′ ¬αr and α k is the smallest variable (wrt ) for k in P ′ ∪N ′ then return{single(α k , t)} else 3.if t = p∈P bp ∧ n∈N ¬bn then ( if p∈P bp ≤ n∈N bn then return {∅} else return ∅) else = i∈I t i then return i∈I norm(t i , M ) else let t ′ be the disjunctive normal form of t in return norm(t ′ , M ) = i≤n σ ′ i and apply it to t with no effect, yielding the inequation ( i≤n sρi)σ ≤ tσ. Let un = i≤n sρi, we have just transformed the problem of proving the relation s ⊑∆ t into the problem of finding an n for which there exists a solution to the tallying problem for {un ≤ t} and ∆. The way to proceed to find n is explained in Section 3.2.3.

	0.	norm(t, M ) =
	1.	if t ∈ M then return {∅} else
	2.
	4.	if t = p∈P (sp→tp) ∧ n∈N ¬(sn→tn) then return
	5.		norm(sn ∧	¬sp, M ∪ {t}) ⊓	norm(sn ∧	¬sp, M ∪ {t} ⊔ norm(	tp ∧ ¬tn, M ∪ {t})	else
		n∈N	p∈P	P ′ ⊂P	p∈P ′	p∈P \P ′
	6.	if t Figure 3. Constraint normalization
	by construction pairwise disjoint (they are formed of distinct fresh
	variables) and disjoint from the variables in t; thus we can merge
	them into a single substitution σ
						Thus the i ≤ t. The domains of σ ′ inequation becomes i≤n (sρi)σ ′ i are

if

  is closed under intersection (see Lemma B.8). Formally, we get the following inference rule for applications

∆ ; Γ ⊢ I a1 : t ∆ ; Γ ⊢ I a2 : s u ∈ t •∆ s ∆ ; Γ ⊢ I a1a2 : u Lemma B.

8. Let t, s be two types and ∆ a set of type variables. If u1 ∈ t •∆ s and u2

  σj]j∈J : j∈J t ′ σj As j 12 ∈J 12 (s1 ∨ s2)σj 12 ≤ j 1 ∈J 1 s1σj 1 ∨ j 2 ∈J 2 s2σj 2 , by subsumption, we can deduce that (e[σj]j∈J ∈t ? e1 : e2)[σj 12 ]j 12 ∈J 12 has the type j 1 ∈J 1 s1σj 1 ∨ j 2 ∈J 2 s2σj 2 . Hence, we eliminate the substitutions that are applied to these two branches.

	j∈J t ′ σj ≤ ¬t and	. . . ∆ ; Γ ⊢ A e1 : s1
	j∈J t ′ σj ≤ t and	. . . ∆ ; Γ ⊢ A e2 : s2
	∆ ; Γ ⊢ A (e[σj]j∈J ∈t ? e1 : e2) : s1 ∨ s2	∀j12 ∈ J12. σj 12 ♯ ∆

∆ ; Γ ⊢ A ((e[σj]j∈J ∈t ? e1 : e2)[σj 12 ]j 12 ∈J 12 ) : j 12 ∈J 12 (s1 ∨ s2)σj 12

  j∈J and e ′ is of the form form e ′ 1 [σj] j∈J ′ , we merge the sets of substitutions [σj]j∈J and [σj] j∈J ′ into one set [σj] j∈J∪J ′ . Otherwise, e and e ′ have different forms. The only possible case where their intersection is well-defined is when they have similar structures but one with instantiations and the other without (i.e., e = e1[σj]j∈J , e ′ = e ′ 1 [σj] j∈J ′ or e = e1[σj]j∈J , e ′ = e ′ 1 [σj] j∈J ′

  ′ 0 ∈t ? e ′ 1 : e ′ 2 : we have erase(ei) = erase(e ′ i ). By induction, ei ⊓ e ′ i exists and erase(ei ⊓ e ′ i ) = erase(ei) = erase(e ′ i ). Therefore (e0∈t ? e1 : e2) ⊓ (e ′

	0 ∈t ? e ′ 1 : e ′ 2 ) exists and
	erase((e0∈t ? e1 : e2) ⊓ (e ′ 0 ∈t ? e ′ 1 : e ′ 2 )) = erase((e0 ⊓ e ′ 0 )∈t ? (e1 ⊓ e ′ 1 ) : (e2 ⊓ e ′ 2 )) = erase(e0 ⊓ e ′ 0 )∈t ? erase(e1 ⊓ e ′ 1 ) : erase(e2 ⊓ e ′ 2 )
	= erase(e0)∈t ? erase(e1) : erase(e2)
	= erase(e0∈t ? e1 : e2)
	Similarly, we also have
	erase((e0∈t ? e1 : e2) ⊓ (e ′ 0 ∈t ? e ′ 1 : e ′ 2 )) = erase(e ′ 0 ∈t ? e ′ 1 : e ′ 2 )
	e[σj]j∈J , e ′ [σj]

  If e ′ = (e ′ 1 , e ′ 2 ), then e ⊓ e ′ = (e1 ⊓ e ′ 1 , e2 ⊓ e ′ 2 ). So the result follows. Otherwise, e ⊓ e ′ = (e1⊓ e ′ 1 , e2 ⊓ e ′ 2 )[σ id , σj]j∈J . Since e ′ ♯ ∆, we have σj ♯ ∆. By (instinter), we have ∆ ; Γ ⊢ (e1 ⊓ e ′ 1 , e2 ⊓ e ′ 2 )[σ id , σj]j∈J : (t1 × t2) ∧ j∈J (t1 × t2)σj. Finally, by (subsum), we get ∆ ; Γ ⊢ (e1 ⊓ e ′ 1 , e2 ⊓ e ′ 2 )[σ id , σj]j∈J : (t1 × t2).As erase(e ′ ) = erase(e1)erase(e2), e ′ is either e ′ 1 e ′ 2 or (e ′ 1 e ′ 2 )[σj]j∈J such that erase(e ′ i ) = erase(ei). By induction, we have ∆ ; Γ ⊢ e1 ⊓ e ′ 1 : t → s and ∆ ; Γ ⊢ e2 ⊓ e ′ 2 : t. Then by (appl), we have ∆ ; Γ ⊢ (e1 ⊓ e ′ 1 )(e2 ⊓ e ′ 2 ) : s. If e ′ = e ′ 1 e ′ 2 , then e ⊓ e ′ = (e1 ⊓ e ′ 1 )(e2 ⊓ e ′ 2 ). So the result follows. Otherwise, e ⊓ e ′ = ((e1 ⊓ e ′ 1 )(e2 ⊓ e ′ 2 ))[σ id , σj]j∈J . Since e ′ ♯ ∆, we have σj ♯ ∆. By (instinter), we have ∆ ; Γ ⊢ ((e1 ⊓ e ′ 1 )(e2 ⊓ e ′ 2 ))[σ id , σj]j∈J : s ∧ j∈J sσj. Finally, by (subsum), we get ∆ ; Γ ⊢ ((e1 ⊓ e ′ 1 )(e2 ⊓ e ′ 2 ))[σ id , σj]j∈J : s.

	(proj): consider the following derivation: ∆ ; Γ ⊢ e0 : t1 × t2 . . . ∆ ; Γ ⊢ πi(e0) : ti As erase(e ′ ) = πi(erase(e0)), e ′ is either πi(e ′ 0 ) or πi(e ′ (proj) 0 )[σj]j∈J such that erase(e ′ 0 ) = erase(e0). By induction, we have ∆ ; Γ ⊢ e0 ⊓ e ′ 0 : (t1 × t2). Then by (proj), we have ∆ ; Γ ⊢ πi(e0 ⊓ e ′ 0 ) : ti. If e ′ = πi(e ′ 0 ), then e ⊓ e ′ = πi(e0 ⊓ e ′ 0 ). So the result follows. Otherwise, e ⊓ e ′ = πi(e0 ⊓ e ′ . . . 0 )[σ (abstr): consider the following derivation: ∀i ∈ I. ∆ ′′ ; Γ, (x : ti) ⊢ e0 : si

′ 1 , e ′ 2 ) or (e ′ 1 , e ′ 2 )[σj]j∈J such that erase(e ′ i ) = erase(ei). By induction, we have ∆ ; Γ ⊢ ei ⊓e ′ i : ti. Then by (pair), we have ∆ ; Γ ⊢ (e1 ⊓e ′ 1 , e2 ⊓e ′ 2 ) : (t1 × t2). id , σj]j∈J . Since e ′ ♯ ∆, we have σj ♯ ∆. By (instinter), we have ∆ ; Γ ⊢ πi(e0 ⊓ e ′ 0 )[σ id , σj]j∈J : ti ∧ j∈J tiσj. Finally, by (subsum), we get ∆ ; Γ ⊢ πi(e0 ⊓ e ′ 0 )[σ id , σj]j∈J : ti. (appl): consider the following derivation: . . . ∆ ; Γ ⊢ e1 : t → s . . . ∆ ; Γ ⊢ e2 : t ∆ ; Γ ⊢ e1e2 : s (pair)

  (INF-CASE-FST): consider the derivation . . . ∆ ; Γ ⊢ I a : t ′ t ′ ⊑∆ t t ′ ⊑∆ ¬t . . . ∆ ; Γ ⊢ I a1 : s ∆ ; Γ ⊢ I (a∈t ? a1 : a2) : s By induction, there exist e, e1 such that erase(e) = a, erase(e1) = a1, ∆ ; Γ ⊢ A e : t ′ , and∆ ; Γ ⊢ A e1 : s. Let [σi 1 ]i 1 ∈I 1 t ′ ⊑∆ t. Since σi 1 ♯ ∆, applying (ALG-INST), we get ∆ ; Γ ⊢ A e[σi 1 ]i 1 ∈I 1 : i 1 ∈I 1 t ′ σi 1 . Let e2be an expression such that erase(e2) = a2. Then we have erase((e[σi 1 ]i 1 ∈I 1 )∈t ? e1 : e2) = (a∈t ? a1 : a2). Finally, since i 1 ∈I 1 t ′ σi 1 ≤ t, by (ALG-CASE-FST), we have ∆ ; Γ ⊢ A ((e[σi 1 ]i 1 ∈I 1 )∈t ? e1 : e2) : s. (INF-CASE-SND): similar to the case of (INF-CASE-FST). ⊢ I (a∈t ? a1 : a2) : s1 ∨ s2 By induction, there exist e, ei such that erase(e) = a, erase(ei) = ai, ∆ ; Γ ⊢ A e : t ′ , and ∆ ; Γ ⊢ A ei : si. According to Definition B.2, we have erase((e∈t ? e1 : e2)) = (a∈t ? a1 : a2). Clearly t ′ ≃ 0. We claim that t ′ ¬t. Let σ id be any identity type substitution. If t ′ ≤ ¬t, then t ′ σ id ≃ t ′ ≤ ¬t, i.e., t ′ ⊑∆ ¬t, which is in contradiction with t ′ ⊑∆ ¬t. Similarly we have t ′ t. Therefore, by (ALG-CASE-SND), we have ∆ ; Γ ⊢ A (e∈t ? e1 : e2) : s1 ∨ s2.

	(INF-CASE-BOTH): consider the derivation . . . ∆ ; Γ ⊢ I a : t ′	    	t ′ ⊑∆ ¬t and t ′ ⊑∆ t and	. . . ∆ ; Γ ⊢ I a1 : s1 . . . ∆ ; Γ ⊢ I a2 : s2
	∆ ; Γ

  By induction, for each i ∈ I, we have ∃t ′ Clearly, we have 0 ⊑∆ s1. If t ′ 0 ⊑∆ 0, then by (INF-CASE-NONE), we get ∆ ; Γ ⊢ I (erase(e)∈t ? erase(e1) : erase(e2)) : 0, that is, ∆ ; Γ ⊢ I erase(e∈t ? e1 : e2) : 0. Clearly, we have 0 ⊑∆ s1 ∨ s2. If t ′ 0 ⊑∆ t, then by (INF-CASE-FST), we get ∆ ; Γ ⊢ I (erase(e)∈t ? erase(e1) : erase(e2)) : t ′ 1 , that is, ∆ ; Γ ⊢ I erase(e∈t ? e1 : e2) : t ′ 1 . Moreover, it is clear that t ′ 1 ⊑∆ s1 ∨ s2, the result follows as well. Similarly for t ′ 0 ⊑∆ ¬t. Otherwise, by (INF-CASE-BOTH), we have ∆ ; Γ ⊢ I (erase(e)∈t ? erase(e1) : erase

	Otherwise, by (INF-CASE-FST), we have
	∆ ; Γ ⊢ I (erase(e)∈t ? erase(e1) : erase(e2)) : t ′ 1 ,
	that is, ∆ ; Γ ⊢ I erase(e∈t ? e1 : e2) : t ′ 1 . The result follows as well.
	(ALG-CASE-SND): similar to the case of (ALG-CASE-FST).
	(ALG-CASE-BOTH): consider the derivation . . . ∆ ; Γ ⊢ A e : t ′	    	t ′ ≤ ¬t and and t ′ ≤ t	. . . ∆ ; Γ ⊢ A e1 : s1 . . .

i . ∆ ′ ; Γ, (x : ti) ⊢ I erase(e) : t ′ i and t ′ i ⊑ ∆ ′ s ′ i . Clearly, we have t ′ i ⊑ ∆ ′ si. By (INF-ABSTR), we have ∆ ; Γ ⊢ I λ ∧ i∈I t i →s i x.erase(e) : i∈I ti → si, that is, ∆ ; Γ ⊢ I erase(λ ∧ i∈I t i →s i x.e) : i∈I ti → si. (ALG-CASE-NONE): consider the derivation . . . ∆ ; Γ ⊢ A e : 0 ∆ ; Γ ⊢ A (e∈t ? e1 : e2) : 0 By induction, we have ∃t ′ 0 . ∆ ; Γ ⊢ I erase(e) : t ′ 0 and t ′ 0 ⊑∆ 0. By (INF-CASE-NONE), we have ∆ ; Γ ⊢ I (erase(e)∈t ? erase(e1) : erase(e2)) : 0, that is, ∆ ; Γ ⊢ I erase(e∈t ? e1 : e2) : 0. (ALG-CASE-FST): consider the derivation . . . ∆ ; Γ ⊢ A e : t ′ t ′ ≤ t . . . ∆ ; Γ ⊢ A e1 : s1 ∆ ; Γ ⊢ A (e∈t ? e1 : e2) : s1 Applying the induction hypothesis twice, we have ∃t ′ 0 . ∆ ; Γ ⊢ I erase(e) : t ′ 0 and t ′ 0 ⊑∆ t ′ , ∃t ′ 1 . ∆ ; Γ ⊢ I erase(e1) : t ′ 1 and t ′ 1 ⊑∆ s1. Clearly, we have t ′ 0 ⊑∆ t. If t ′ 0 ⊑∆ ¬t, then by Lemma B.4, we have t ′ 0 ≤∆ 0. By (INF-CASE-NONE), we get ∆ ; Γ ⊢ I (erase(e)∈t ? erase(e1) : erase(e2)) : 0, that is, ∆ ; Γ ⊢ I erase(e∈t ? e1 : e2) : 0. ∆ ; Γ ⊢ A e2 : s2 ∆ ; Γ ⊢ A (e∈t ? e1 : e2) : s1 ∨ s2 By induction, we have ∃t ′ 0 . ∆ ; Γ ⊢ I erase(e) : t ′ 0 and t ′ 0 ⊑∆ t ′ , ∃t ′ 1 . ∆ ; Γ ⊢ I erase(e1) : t ′ 1 and t ′ 1 ⊑∆ s1, ∃t ′ 2 . ∆ ; Γ ⊢ I erase(e2) : t ′ 2 and t ′ 2 ⊑∆ s2.

  [START_REF] Robie | XQuery 3.0: An XML query language[END_REF], we have σ n C ′ 2 . Moreover, from σ n C| tlv(t) , we have σ n C ′ 1 . Thus, σ n C ′ and a fortiori σ n {(t, ≤, 0)}. C.12 (Completeness). Let C be a constraint-set such that ∅ ⊢ N C S . For all substitution σ, if σ C, then there existsC ′ ∈ S such that σ C ′ .The result is then a direct consequence of the first item (indeed, we have σ C(∅) for all σ). We prove the two items simultaneously by induction on the derivations of Σ ⊢ N C I}, we have in particular σ {(ti ci t ′ i )} for all i. By induction, there exists Ci ∈ Si such that σ Ci. So σ i∈I Ci. Moreover, according to Definition C.4, i∈I Ci must be in i∈I Si. Therefore, the result follows. (NSYM): if σ {(t ′ ≥ t)}, then σ {(t ≤ t ′ )}. By induction, the result follows. (NZERO): since σ {(t ≤ t ′ )}, we can substract t ′ from both sides obtain σ {(t ∧ ¬t ′ ≤ 0)}. By induction, the result follows.

	Lemma Proof. We prove the following stronger statements.
	(1) Assume Σ ⊢ N C σ C ′ .	S . For all σ, if σ	C(Σ) and σ	C, then there exists C ′ ∈ S such that
	(2) Assume Σ ⊢ * N C σ C ′ .	S . For all σ, if σ	C(Σ) and σ	C, then there exists C ′ ∈ S such that
				S and Σ ⊢ * N C	S .
	(NEMPTY): straightforward.
	(NJOIN): as σ {(ti ci t ′ i ) | i ∈

  Case 2: τ = ps∈Ps (wp s ×vp s )∧ ns∈Ns ¬(wn s ×vn s )∧ p t ∈P t (wp t ×vp t )∧ n t ∈N t ¬(wn t ×vn t ), where Ps, Ns are from s and Pt, Nt are from t. Since ∅ ⊢ N {τ, ≤, 0)} ∅, by the rule (NPROD), there exist two sets N ′ s ⊆ Ns and N ′ (wp s × vp s ) ∧ ns∈Ns ¬(wn s × vn s ) and τt = p t ∈P t (wp t × vp t ) ∧ n t ∈N t ¬(wn t × vn t ). Case 3: τ = ps∈Ps (wp s → vp s )∧ ns∈Ns ¬(wn s → vn s )∧ p t ∈P t (wp t → vp t )∧ n t ∈N t ¬(wn t → vn t ), where Ps, Ns are from s and Pt, Nt are from t. Since ∅ ⊢ N {τ, ≤, 0)} ∅, by the rule (NARROW), for all w → v ∈ Ns ∪ Nt, there exist a set P ′ s ⊆ Ps and a set

						t ⊆ Nt such that
		 	∅ ⊢ N {	wp s ∧	¬wn s ∧		wp t ∧	¬wn t , ≤, 0)}	∅
		 		ps∈Ps	ns∈N ′ s	p t ∈P t	n t ∈N ′ t
		 	∅ ⊢ N {	vp s ∧		¬vn s ∧		vp t ∧	¬vn t , ≤, 0)}	∅
				ps∈Ps	ns∈Ns\N ′ s	p t ∈P t	n t ∈N t \N ′ t
	By induction, we have
	 	∅ ⊢ N {	(	wp s ∧	¬wn s )ρj ∧	(		wp t ∧	¬wn t )ρi, ≤, 0)}	∅
	 		j∈J	ps∈Ps	ns∈N ′ s	i∈I	p t ∈P t	n t ∈N ′ t
	 	∅ ⊢ N {	(	vp s ∧		¬vn s )ρj ∧	(	vp t ∧	¬vn t )ρi, ≤, 0)}	∅
			j∈J	ps∈Ps	ns∈Ns\N ′ s		i∈I	p t ∈P t	n t ∈N t \N ′ t
	Then by the rule (NPROD) again, we get
					∅ ⊢ N {	(τs)ρj ∧		(τt)ρi, ≤, 0)}	∅
						j∈J	i∈I
	where τs =

ps∈Ps

  where τs = ps∈Ps (wp s → vp s ) ∧ ns∈Ns ¬(wn s → vn s ) and τt = p t ∈P t (wp t → vp t ) ∧ n t ∈N t ¬(wn t → vn t ). Case 4: τ = ( ks∈Ks τ ks ) ∧ ( k t ∈K t τ k t ), where τ ks and τ k t are single normal forms. As ∅ ⊢ N {(τ, ≤, 0)} ∅, there must exist at least one ks ∈ Ks and at least one kt ∈ Kt such that ∅ ⊢ N {(τ ks ∧ τ k t , ≤, 0)} ∅. By Cases (1) -(3), the result follows.

		Pt
	or
	∅ ⊢ N {	(	vp s )ρj ∧	(	vp t )ρi ∧ ¬vρ, ≤, 0)}	∅
	j∈J	ps∈Ps\P ′ s	i∈I	p t ∈P t \P ′ t
	Then by the rule (NARROW) again, we get
		∅ ⊢ N {	(τs)ρj ∧		(τt)ρi, ≤, 0)}	∅
		j∈J	i∈I

  Let t, s be two types, γ a fresh type variable and [ρi]i∈I , [ρj]j∈J two sets of general renamings. If ∅ ⊢ N {(t, ≤, 0 → 1), (t, ≤, s → γ)} ∅, then ∅ ⊢ N {( i∈I tρi, ≤, 0 → 1), ( i∈I tρi, ≤ , ( j∈J sρj) → γ)} ∅.

	Proof. As ∅ ⊢ N {(t, ≤, 0 → 1), (t, ≤, s → γ)}	∅, then either ∅ ⊢ N {(t, ≤, 0 → 1)}	∅
	or ∅ ⊢ N {(t, ≤, s → γ)}	∅. If the first one holds, then according to Lemma C.19, we have
	∅ ⊢ N {( i∈I tρi, ≤, 0 → 1)}	∅, and a fortiori
	∅ ⊢ N {(	tρi, ≤, 0 → 1), (	tρi, ≤, (	sρj) → γ)}	∅
	i∈I		i∈I	j∈J
	Assume that ∅ ⊢ N {(t, ≤, s → γ)}	∅. Without loss of generality, we consider the disjunctive normal
	form τ of t:
	τ

∅, ∅ ⊢ M S C S , then the result of the merging of C is S . Lemma C.53.

Table 1 .

 1 and Heuristic number Hp(s) for the copies of t

	Shape of s	Number Hp(s)
	i∈I si	Σi∈I Hp(si)

Table 2 .

 2 Heuristic number Hq(dom(t)) for the copies of s Shape of dom(t) Number Hq(dom(t))i∈I ti i∈I Hq(ti) + 1 i∈P bi ∧ i∈N ¬bi ∧ i∈P 1 αi ∧ i∈N 1 ¬αi 1 i∈P (t 1 i × t 2 i ) ∧ i∈N ¬(t 1 i × t 2 i ) N ′ ⊆N Hq(t 1 N ′ × t 2

	N ′ )

  x) ∩ dom(Σ) = ∅ 16 xΣ otherwise λ t p.e Σ,Ξ = λ t Σ x&p. e sel(x,t,Σ),Ξ if var(t) ∩ dom(Σ) = ∅ 16 (x fresh) λt Σ x&p. e sel(x,t,Σ),Ξ otherwise

(x fresh)

  table: # of tests Total Time Average Time Median Time Min. Time Max.

						Time
	1 859	27s	14ms	2.1ms	0.1ms	2.090s
	The worst time (2.09s) is the one for the local type inference of

1 map (length & hd & tl & nth & rev & 2 append & rev_append & concat & flatten & 3 iter & iteri & map & mapi & rev_map & fold_left)

  table reports a sample of the cpu times for different n's

	arity n # of tests Total Time for all the tests
	10	60	0m0.033s
	15	90	0m0.272s
	20	120	0m0.768s
	25	150	2m39.689s

For map even we need to infer just two instantiations, namely, { (γ\Int) / α , (γ\Int) / β } and { (γ∨Int) / α , (γ\Int) ∨ Bool / β }. The type in (1) is redundant since the first type of the intersection is an instance (eg, for γ=Int) of the third. We included it just for the sake of the presentation.

Actually, for every type t, all types of the form 0→t are equivalent and each of them denotes the set of all functions.

Equivalence of t ≤ 0 and the two following constraints is easily derived from the De Morgan's laws and the property t 1 ≤ t 2 ⇐⇒ t 1 ∧ ¬t 2 ≤ 0.

Precisely, we have t 1 = i=1..|I| t 1 i and t 2 = i=1..|J| t 2 i where for h = 1, 2 each t h i is obtained from t h by renaming the variables not in ∆ into fresh variables.

Following the OCaml convention, in the concrete syntax type variables start by a quote. To enhance readability here we pretty print them by Greek letters and so write α → β rather than 'a -> 'b.

Γ ⊢ R c : bc {∅} (R-CONST) Γ ⊢ R x : Γ(x) {∅} (R-VAR) Γ ⊢ R m 1 : t 1 S 1 Γ ⊢ R m 2 : t 2 S 2 Γ ⊢ R m 1 m 2 : α S 1 ⊓ S 2 ⊓ {{(t 1 ≤ t 2 → α)}} (R-APPL) Γ, x : α ⊢ R m : t S Γ ⊢ R λx.m : α → β S ⊓ {{(t ≤ β)}} (R-ABSTR) (R-CASE) S = (S 0 ⊓ {{(t 0 ≤ 0)}}) ⊔ (S 0 ⊓ S 1 ⊓ {{(t 0 ≤ t), (t 1 ≤ α)}}) ⊔ (S 0 ⊓ S 2 ⊓ {{(t 0 ≤ ¬t), (t 2 ≤ α)}}) ⊔ (S 0 ⊓ S 1 ⊓ S 2 ⊓ {{(t 1 ∨ t 2 ≤ α)}}) Γ ⊢ R m 0 : t 0 S 0 Γ ⊢ R m 1 : t 1 S 1 Γ ⊢ R m 2 : t 2 S 2 Γ ⊢ R (m 0 ∈t ? m 1 : m 2 ) : α Swhere α, α i and β in each rule are fresh type variables.

If one of the sub-derivations does not end with (ALG-INST), we can apply a trivial instance of (ALG-INST) with an identity substitution σ id .

Or by s ∨ (α ′ ∧ t).

Or, equivalently, α = t 1 ∨ (α ′ ∧ t 2 ). Besides, in practice, if only α ≥ t 1 (α ≤ t 2 resp.) and all the occurrences of α in the co-domain of the function type are positive (negative resp.), we can use α = t 1 (α = t 2 resp.) instead, and the completeness is ensured by subsumption.

In the current implementation we assume that the type variables in the function type always have smaller orders than those in the argument type.

Acknowledgments. We want to thank the reviewers of POPL who gave detailed suggestions to improve our presentation. This work was partially supported by the ANR TYPEX project n. ANR-11-BS02-007. Zhiwu Xu was also partially supported by an Eiffel scholarship of French Ministry of Foreign Affairs and by the grant n. 61070038 of the National Natural Science Foundation of China.

Lemma C.20 (Soundness). Let C be a normalized constraint-set. If ∅, ∅ ⊢ M S C S , then for all normalized constraint-set C ′ ∈ S and all substitution σ, we have σ C ′ ⇒ σ C.

Proof. We prove the following statements.

• Assume ⊢ M C C ′ . For all σ, if σ C ′ , then σ C. • Assume Σp, CΣ ⊢ S C S . For all σ and C0 ∈ S , if σ C0, then σ CΣ ∪ C.

Clearly, these two statements imply the lemma. The first statement is straightforward. The proof of the second statement proceeds by induction of the derivation of Σp, CΣ ⊢ S C S .

(SHYP): by induction, we have σ (CΣ ∪ {(α ≥ t1), (α ≤ t2)}) ∪ C, that is σ CΣ ∪ ({(α ≥ t1), (α ≤ t2)} ∪ C). S . Then for all substitution σ, if σ C, then there exists C ′ ∈ S such that σ C ′ .

Proof. We prove the following statements.

S . For all σ, if σ CΣ ∪ C, then there exists C0 ∈ S such that σ C0.

Clearly, these two statements imply the lemma. The first statement is straightforward. The proof of the second statement proceeds by induction of the derivation of Σp, CΣ ⊢ S C S .

(SHYP): the result follows by induction.

(SASSUM): as σ CΣ ∪ ({(α ≥ t1), (α ≤ t2)} ∪ C), we have σ {(t1 ≤ t2)}. As ∅ ⊢ N {(t1 ≤ t2)} S , applying Lemma C.12, there exists

Clearly we have σ C ′ and C ′ ∈ S ′ . By induction on the premise Σp ∪ {(t1, t2)}, ∅ ⊢ M S C ′ S C ′ , there exists C0 ∈ S C ′ such that σ C0. Moreover, it is clear that C0 ∈ C ′ ∈S ′ S C ′ . Therefore, the result follows. (SDONE): straightforward.

Lemma C. 22 (Termination). Let C be a finite normalized constraint-set. Then ∅, ∅ ⊢ M S C terminates.

Proof. Let T be the set of types occurring in C. As C is finite, T is finite as well. Let be a plinth such that T ⊆ . Then when we saturate a fresh constraint (t1, ≤, t2) during the process of ∅, ∅ ⊢ M S C, (t1, t2) would belong to × . According to Lemma C.14, we know that ∅ ⊢ N {(t1, ≤, t2)} terminates. Moreover,the termination of the merging of the lower bounds or the upper bounds of a same type variable is straightforward. Definition C. . Let C1, C2 ⊆ C be two normalized constraint-sets. We say C1 is a sub-constraint of C2, denoted as C1 ⋖ C2, if for all (α, c, t) ∈ C1, there exists (α, c, t ′ ) ∈ C2 such that t ′ c t, where c ∈ {≤, ≥}.

Lemma C.24. Let C1, C2 ⊆ C be two normalized constraint-sets and C1 ⋖ C2. Then for all substitution σ, if σ C2, then σ C1.

Proof. Considering any constraint (α, c, t) ∈ C1, there exists (α, c, t ′ ) ∈ C2 and t ′ c t, where c ∈ {≤, ≥}. Since σ C2, then σ(α) c t ′ σ. Moreover, as t ′ c t, we have t ′ σ c tσ. Thus σ(α) c tσ.

Definition C.25. Let C ⊆ C be a normalized constraint-set. We say C is saturated if for each type variable α ∈ dom(C), [START_REF] Aiken | Type inclusion constraints and type inference[END_REF] there exists at most one form (α ≥ t1) ∈ C, [START_REF] Benzaken | CDuce: an XML-friendly general purpose language[END_REF] there exists at most one form (α ≤ t2) ∈ C, (3) if (α ≥ t1), (α ≤ t2) ∈ C, then ∅ ⊢ N {(t1 ≤ t2)} S and there exists C ′ ∈ S such that C ′ is a sub-constraint of C (i.e., C ′ ⋖ C).

Lemma C.26. Let C be a finite normalized constraint-set and ∅, ∅ ⊢ M S C S . Then for all normalized constraint set C ′ ∈ S , C ′ is saturated.

Proof. We prove a stronger statement: assume Σp, CΣ ⊢ M S C S . If

The proof of conditions (1) and (2) for a saturated constraint-set is straightforward for all C0 ∈ S . The proof of the condition (3) proceeds by induction on the derivation Σp, CΣ ⊢ S C S and a case analysis on the last rule used in the derivation.

(SHYP): as (t1, t2) ∈ Σp, the conditions (i) and (ii) hold for the premise. By induction, the result follows. (SASSUME): take any premise

S , there exists C0 ∈ S such that C0 ⋖ C ′′ . Thus the condition (i) holds for the premise. Moreover, the condition (ii) holds straightforwardly for premise. By induction, the result follows. (SDONE): the result follows by the conditions (i) and (ii).

Lemma C.27 (Finiteness

Proof. The merging of the lower bounds (or the upper bounds) of a same type variable preserves the orders. The result of saturation is well-ordered by Lemma C.17.

Normalization and merging may produce redundant constraint-sets. For example, consider the constraintset {(α × β), ≤, (Int × Bool)}. Applying the rule (NPROD), the normalization of this set is {{(α, ≤, 0)}, {(β, ≤, 0)}, {(α, ≤, 0), (β, ≤, 0)}, {(α, ≤, Int), (β, ≤, Bool)}}. Clearly each constraint-set is a saturated one. Note that {(α, ≤, 0), (β, ≤, 0)} is redundant, since any solution of this constraint-set is a solution of {(α, ≤, 0)} and {(β, ≤, 0)}. Therefore it is safe to eliminate it. Generally, for any two different normalized constraint sets C1, C2 ∈ S , if C1 ⋖ C2, then according to Lemma C.24, any solution of C2 is a solution of C1. Therefore, C2 can be eliminated from S . Definition C.29. Let S be a set of normalized constraint-sets. We say that S is minimal if for any two different normalized constraint-sets C1, C2 ∈ S , neither C1 ⋖C2 nor C2 ⋖C1. Moreover, we say S ≃ S ′ if for all substitution σ such that ∃C ∈ S . σ C ⇐⇒ ∃C ′ ∈ S ′ . σ C ′ . Lemma C.30. Let C be a well-ordered normalized constraint-set and ∅, ∅ ⊢ M S C S . Then there exists a minimal set S0 such that S0 ≃ S .

Proof. By eliminating the redundant constraint-sets in S .

C.1.3 Constraint solving

From constraints to equations. Given a well-ordered saturated constraint-set, we transform it into an equivalent equation system. This shows that the type tallying problem is essentially a unification problem.

Definition C.31 (Equation system

). An equation system E is a set of equations of the form α = t such that there exists at most one equation in E for every type variable α. We define the domain of E, written dom(E), as the set {α | ∃t . α = t ∈ E}.

Definition C.32 (Equation system solution). Let E be an equation system. A solution to E is a substitution

From a normalized constraint-set C, we obtain some explicit conditions for the substitution σ we want to construct from C. For instance, from the constraint α ≤ t (resp. α ≥ t), we know that the type substituted for α must be a subtype of t (resp. a super type of t).

We assume that each type variable α ∈ dom(C) has a lower bound t1 and a upper bound t2 using, if necessary, the fact that 0 ≤ α ≤ 1. Formally, we rewrite C as follows:

We then transform each constraint t1 ≤ α ≤ t2 in C into an equation α = (t1 ∨ α ′ ) ∧ t2 12 , where α ′ is a fresh type variable. The type (t1 ∨ α ′ ) ∧ t2 ranges from t1 to t2, so the equation α = (t1 ∨ α ′ ) ∧ t2 expresses the constraint that t1 ≤ α ≤ t2, as wished. We prove the soundness and completeness of this transformation.

To prove soundness, we define the rank n satisfaction predicate n for equation systems, which is similar to the one for constraint-sets.

Lemma C.33 (Soundness). Let C ⊆ C be a well-ordered saturated normalized constraint-set and E its transformed equation system. Then for all substitution σ, if σ E then σ C.

Proof. Without loss of generality, we assume that each type variable α ∈ dom(C) has a lower bound and an upper bound, that is t1 ≤ α ≤ t2 ∈ C. We write O(C1) < O(C2) if O(α) < O(β) for all α ∈ dom(C1) and all β ∈ dom(C2). We first prove a stronger statement:

(*) for all σ, n and

Here CΣ denotes the set of constraints that have been checked. The proof proceeds by induction on |C \CΣ|.

Clearly, there exists a corresponding equation α = (t1

≃n 0 Therefore, σ(α) ≤n t2σ. Consider the constraint (t1, ≤, α). We have t1σ ∧ ¬σ(α) ≃n t1σ ∧ ¬((t1 ∨ α ′ ) ∧ t2)σ ≃n t1σ ∧ ¬t2σ What remains to do is to check the subtyping relation t1σ ∧ ¬t2σ ≤n 0, that is, to check that the judgement σ n {(t1 ≤ t2)} holds. Since the whole constraint-set C is saturated, according to Definition C.25, we have ∅ ⊢ N {(t1 ≤ t2)} S and there exists

From the premise and Lemma C.24, we have σ n C ′ | tlv(t 1 )∪tlv(t 2 ) and σ n-1 C ′ \ C ′ | tlv(t 1 )∪tlv(t 2 ) . Then, by Lemma C.11, we get σ n {(t1 ≤ t2)}. Finally, consider the constraint-set C \ (CΣ ∪ {(t1 ≤ α ≤ t2)}). By induction, we have σ n C \ (CΣ ∪ {(t1 ≤ α ≤ t2)}). Thus the result follows.

Finally, we explain how to prove the lemma with the statement (*). Take CΣ = ∅. Since σ E, we have σ n E for all n. Trivially, we have σ 0 C. This can be used to prove σ 1 C. Since σ 1 E, by (*), we get σ 1 C, which will be used to prove σ 2 C. Consequently, we can get σ n C for all n, which clearly implies the lemma.

Lemma C.34 (Completeness).

Let C ⊆ C be a saturated normalized constraint-set and E its transformed equation system. Then for all substitution σ, if σ C then there exists σ ′ such that σ ′ ♯ σ and σ ∪ σ ′ E.

Definition C.35. Let E be an equation system and O an ordering on dom(E). We say that E is well ordered if for all α = tα ∈ E, we have O(α) < O(β) for all β ∈ tlv(tα) ∩ dom(E).

Lemma C.36. Let C be a well-ordered saturated normalized constraint-set and E its transformed equation system. Then E is well ordered.

Thus the result follows.

Solution of Equation Systems. We now extract a solution (i.e., a substitution) from the equation system we build from C. In an equation α = tα, α may also appear in the type tα; such an equality reminds the definition of a recursive type. As a first step, we introduce a recursion operator µ in all the equations of the system, transforming α = tα into α = µxα. tα{ xα / α }. This ensures that type variables do not appear in the right-hand side of the equalities, making the whole solving process easier. If some recursion operators are in fact not needed in the solution (i.e., we have α = µxα.tα with xα / ∈ fv(tα)), then we can simply eliminate them.

If the equation system contains only one equation, then this equation is immediately a substitution. Otherwise, consider the equation system {α = µxα. tα} ∪ E, where E contains only equations closed with the recursion operator µ as explained above. The next step is to substitute the content expression µxα. tα for all the occurrences of α in equations in E. In detail, let β = µx β . t β ∈ E. Since tα may contain some occurrences of β and these occurrences are clearly bounded by µx β , we in fact replace the equation

}, yielding a new equation system E ′ . Finally, assume that the equation system E ′ (which has fewer equations) has a solution σ ′ . Then the substitution { tασ ′ / α } ⊕ σ ′ is a solution to the original equation system {α = µxα. tα} ∪ E. The solving algorithm Unify() is given in Figure 10.

Require: Proof. The algorithm Unify() consists of two steps: (i) transform types into recursive types and (ii) extract the substitution. After the first step, for each equation (α = tα) ∈ E, we have α / ∈ var(tα). Consider the second step. Let var(E) = (α=tα)∈E var(tα) and S = V \ S, where S is a set of type variables. We prove a stronger statement:

The proof proceeds by induction on E:

Then there exists a substitution σ ′′ such that σ ′′ = Unify(E ′′ ) and σ = { tασ ′′ / α } ⊕ σ ′′ . By induction, we have ∀β ∈ dom(σ ′′ ). var(σ ′′ (β)) ∩ (dom(σ ′′ ) ∪ var(E ′′ )) = ∅ and dom(σ ′′ ) = dom(E ′′ ). As α / ∈ dom(E ′′ ), we have α / ∈ dom(σ ′′ ) and then dom(σ) = dom(σ ′′ ) ∪ {α} = dom(E). Moreover, α / ∈ var(E ′′ ), then dom(σ) ⊂ dom(σ ′′ ) ∪ var(E ′′ ). Thus, for all β ∈ dom(σ ′′ ), we have var(σ ′′ (β)) ∩ dom(σ) = ∅. Consider tασ ′′ . It is clear that var(tασ ′′ ) ∩ dom(σ) = ∅. Besides, the algorithm does not introduce any fresh variable, then for all β ∈ dom(σ), we have var(t β )∩var(E) = ∅. Therefore, the result follows.

Lemma C.39 (Soundness). Let E be an equation system. If σ = Unify(E), then σ E.

Proof. By induction on E. Clearly, given an equation system E, the algorithm Unify(E) terminates with a substitution σ.

Lemma C.41 (Termination)

. Given an equation system E, the algorithm Unify(E) terminates.

Proof. By induction on the number of equations in E.

Definition C.42. Let σ, σ ′ be two substitutions. We say σ ≃ σ ′ if and only if ∀α. σ(α) ≃ σ ′ (α).

Lemma C.43 (Completeness)

. Let E be an equation system. For all substitution σ, if σ E, then there exist σ0 and σ ′ such that σ0 = Unify(E) and σ ≃ σ ′ • σ0.

Proof. According to Lemma C.41, there exists σ0 such that σ0 = Unify(E). For any α / ∈ dom(σ0), clearly we have ασ0σ = ασ and then ασ0σ ≃ ασ. What remains to prove is that if σ E and σ0 = Unify(E) then ∀α ∈ dom(σ0). ασ0σ ≃ ασ. The proof proceeds by induction on E:

Then there exists a substitution σ ′′ such that σ ′′ = Unify(E ′′ ) and σ0 = { tασ ′′ / α } ⊕ σ ′′ . Considering each equation

(as σ E) Therefore, the result follows.

In our calculus, a type is well-formed if and only if the recursion traverses a constructor. In other words, the recursive variable should not appear at the top level of the recursive content. For example, the type µx. x ∨ t is not well-formed. To make the substitutions usable, we should avoid these substitutions with ill-formed types. Fortunately, this can been done by giving an ordering on the domain of an equation system to make sure that the equation system is well-ordered.

Lemma C.44. Let E be a well-ordered equation system. If σ = Unify(E), then for all α ∈ dom(σ), σ(α) is well-formed.

Proof. Assume that there exists an ill-formed σ(α). That is, σ(α) = µx. t where x occurs at the top level of t. According to the algorithm Unify(), there exists a sequence of equations (α =)α0 = tα 0 , α1 = tα 1 , . . . , αn = tα n such that αi ∈ tlv(tα i-1 ) and α0 ∈ tlv(tα n ) where i ∈ {1, . . . , n} and n ≥ 0. According to Definition C.35, O(αi-1) < O(αi) and O(αn) < O(α0). Therefore, we have O(α0) < O(α1) < . . . < O(αn) < O(α0), which is impossible. Thus the result follows.

As mentioned above, there may be some useless recursion constructor µ. They can be eliminated by checking whether the recursive variable appears in the content expression or not. Moreover, if a recursive type is empty (which can be checked with the subtyping algorithm), then it can be replaced by 0.

C.1.4 The complete algorithm

To conclude, we now describe the solving procedure Sol∆(C) for the type tallying problem C. We first normalize C into a finite set S of well-ordered normalized constraint-sets (Step 1). If S is empty, then there are no solutions to C. Otherwise, each constraint-set Ci ∈ S is merged and saturated into a finite set SC i of well-order saturated normalized constraint-sets (Step 2). Then all these sets are collected into another set S ′ (i.e., S ′ = C i ∈S SC i ). If S ′ is empty, then there are no solutions to C. Otherwise, for each constraint-set C ′ i ∈ S ′ , we transform C ′ i into an equation system Ei and then construct a general solution σi from Ei (Step 3). Finally, we collect all the solutions σi, yielding a set Θ of solutions to C. We write Sol∆(C) Θ if Sol∆(C) terminates with Θ, and we call Θ the solution of the type tallying problem C.

C.2 Type-Substitution Inference Algorithm

In Section B, we presented a sound and complete inference system, which is parametric in the decision procedures for ⊑∆, ∐ i ∆ (), and •∆. In this section we tackle the problem of computing these operators. We focus on the application problem •∆, since the other two can be solved similarly. Recall that to compute t •∆ s, we have to find two sets of substitutions [σi]i∈I and [σj]j∈J such that ∀h ∈ I ∪ J. σ h ♯ ∆ and

This problem is more general than the other two problems. If we are able to decide inequation [START_REF] Okasaki | Purely Functional Data Structures[END_REF], it means that we are able to decide s ′ ⊑∆ t ′ for any s ′ and t ′ , just by considering t ′ ground. Therefore we can decide ⊑∆. We can also decide [σi]i∈I s ⊑∆ 1 × 1 for all s, and therefore compute ∐ i ∆ (s). Let the cardinalities of I and J be p and q respectively. We first show that for fixed p and q, we can reduce the application problem to a type tallying problem. Note that if we increase p, the type on the right of Inequality ( 19) is larger, and if we increase q the type on the left is smaller. Namely, the larger p and q are, the higher the chances that the inequality holds. Therefore, we can search for cardinalities that make the inequality hold by starting from p = q = 1, and then by increasing p and q in a dove-tail order until we get a solution. This gives us a semi-decision procedure for the general application problem. In order to ensure termination, we give some heuristics based on the shapes of s and t to set upper bounds for p and q.

C.2.1 Application problem with fixed cardinalities

We explain how to reduce the application problem with fixed cardinalities for I and J to a type tallying problem. Without loss of generality, we can split each substitution σ k (k ∈ I ∪ J) into two substitutions: a renaming substitution ρ k that maps each variable in the domain of σ k into a fresh variable and a second substitution σ ′ k such that σ k = σ ′ k • ρ k . The two inequalities then can be rewritten as

The domains of the substitutions σ ′ k are pairwise distinct, since they are composed by fresh type variables. We can therefore merge the σ ′ k into one substitution σ = k∈I∪J σ ′ k . We can then further rewrite the two inequalities as

where t ′ = ( i∈I tρi) and s ′ = ( j∈J sρj). As t ′ σ ≤ 0 → 1, then t ′ σ must be a function type. Then according to Lemmas C.12 and C.13 in the companion paper [START_REF] Castagna | Polymorphic functions with set-theoretic types. Part 1: Syntax, semantics, and evaluation[END_REF], we can reduce these two inequalities to the constraint set 13 : C = {(t ′ , ≤, 0 → 1), (t ′ , ≤, s ′ → γ)} where γ is a fresh type variable. We have reduced the original application problem t •∆ s to solving C, which can be done as explained in Section C.1. We write AppFix ∆ (t, s) for the algorithm of the application problem with fixed cardinalities t •∆ s and AppFix ∆ (t, s)

Θ if AppFix ∆ (t, s) terminates with Θ.

Lemma C.49. Let t, s be two types and γ a type variable such that γ / ∈ var(t) ∪ var(s). Then for all substitution σ, if tσ ≤ sσ → γσ, then sσ ≤ dom(tσ) and σ(γ) ≥ tσ • sσ. 13 The first constraint (t ′ , ≤, 0 → 1) can be eliminated since it is implied by the second one.

Proof. Consider any substitution σ. As tσ ≤ sσ → γσ, by Lemma C.12 in the companion paper [START_REF] Castagna | Polymorphic functions with set-theoretic types. Part 1: Syntax, semantics, and evaluation[END_REF], we have sσ ≤ dom(tσ). Then by Lemma C.13 in the companion paper [START_REF] Castagna | Polymorphic functions with set-theoretic types. Part 1: Syntax, semantics, and evaluation[END_REF], we get σ(γ) ≥ tσ • sσ.

Lemma C.50. Let t, s be two types and γ a type variable such that γ / ∈ var(t) ∪ var(s). Then for all substitution σ, if sσ ≤ dom(tσ) and γ / ∈ dom(σ), then there exists σ ′ such that σ ′ ♯ σ and t(σ

Proof. Consider any substitution σ. As sσ ≤ dom(tσ), by Lemma C.13 in the companion paper [START_REF] Castagna | Polymorphic functions with set-theoretic types. Part 1: Syntax, semantics, and evaluation[END_REF], the type (tσ) • (sσ) exists and tσ ≤ sσ → ((tσ)

Note that the solution of the γ introduced in the constraint (t, ≤, s → γ) represents a result type for the application of t to s. In particular, completeness for the tallying problem ensures that each solution will assign to γ (which occurs in a covariant position) the minimum type for that solution. So the minimum solutions for γ are in t •∆ s (see the substitution σ ′ (γ) = (tσ) • (sσ) in the proof of Lemma C.50).

Theorem C.51 (Soundness

C.2.2 General application problem

Now we take the cardinalities of I and J into account to solve the general application problem. We start with I and J both of cardinality 1 and explore all the possible combinations of the cardinalities of I and J by, say, a dove-tail order until we get a solution. More precisely, the algorithm consists of two steps:

Step A: we generate a constraint set as explained in Section C.2.1 and apply the tallying solving algorithm described in Section C.1, yielding either a solution or a failure.

Step B: if all attempts to solve the constraint sets have failed at Step 1 of the tallying solving algorithm given at the beginning of Section C.1.1, then fail (the expression is not typable). If they all failed but at least one did not fail in Step 1, then increment the cardinalities I and J to their successor in the dovetail order and start from Step A again. Otherwise all substitutions found by the algorithm are solutions of the application problem.

Notice that the algorithm returns a failure only if the solving of the constraint-set fails at Step 1 of the algorithm for the tallying problem. The reason is that up to Step 1 all the constraints at issue are on distinct occurrences of type variables: if they fail there is no possible expansion that can make the constraintset satisfiable (see Lemma C.53). For example, the function map can not be applied to any integer, as the normalization of {(Int, ≤, α → β)} is empty (and even for any expansion of α → β). In Step 2 instead constraints of different occurrences of a same variable are merged. Thus even if the constraints fail it may be the case that they will be satisfied by expanding different occurrences of a same variable into different variables. Therefore an expansion is tried. For example, consider the application of a function of type ((Int → Int) ∧ (Bool → Bool)) → t to an argument of type α → α. We start with the constraint

). The tallying algorithm first normalizes it into the set {(α, ≤, Int), (α, ≥, Int), (α, ≤, Bool), (α, ≥, Bool)} (Step 1).

But it fails at

Step 2 as neither Int ≤ Bool nor Bool ≤ Int hold. However, if we expand α → α, the constraint to be solved becomes

and one of the constraint-set of its normalization is {(α1, ≤, Int), (α1, ≥, Int), (α2, ≤, Bool), (α2, ≥, Bool)} The conflict between Int and Bool disappears and we can find a solution to the expanded constraint.

Note that we keep trying expansion without giving any bound on the cardinalities I and J, so the procedure may not terminate, which makes it only a semi-algorithm. The following lemma justifies why we do not try to expand if normalization (i.e., Step 1 of the tallying algorithm) fails.

D. Type reconstruction

We define an implicit calculus without interfaces, for which we define a reconstruction system.

Definition D.1. An implicit expression m is an expression without any interfaces (or type substitutions). It is inductively generated by the following grammar:

m

The type reconstruction for expressions has the form Γ ⊢ R e : t S , which states that under the typing environment Γ, e has type t if there exists at least one constraint-set C in the set of constraint-sets S such that C are satisfied. The type reconstruction rules are given in Figure 11.

where α, αi and β in each rule are fresh type variables.

Figure 11. Type reconstruction rules

Most of the rules, except the rules for type cases, are standard but differ from most of the type inference of other work in that they generate a set of constraint-sets rather than a single constraint-set. This is due to the type inference for type-cases. There are four possible cases for type-cases ((RECON-CASE)): (i) if no branch is selected, then the type t0 inferred for the argument m0 should be 0 (and the result type can be any type); (ii) if the first branch is selected, then the type t0 should be a subtype of t and the result type α for the whole type-case should be a super-type of the type t1 inferred for the first branch m1; (iii) if the second branch is selected, then the type t0 should be a subtype of ¬t and the result type α should be a super-type of the type t2 inferred for the second branch m2; and (iv) both branches are selected, then the result type α should be a super-type of the union of t1 and t2 (note that the condition for t0 is the one that does not satisfy (i), (ii) and (iii)). Therefore, there are four possible solutions for type-cases and thus four possible constraint-sets. Finally, the rule (RECON-CASE-VAR) deals with the type inference for the special binding type-case introduced in Appendix E in the companion paper [START_REF] Castagna | Polymorphic functions with set-theoretic types. Part 1: Syntax, semantics, and evaluation[END_REF].

Let m be an implicit expression such that Γ ⊢ R m : t S . By inserting into m those types form of α → β introduced by the derivation of Γ ⊢ R m : t S for the λ-abstractions in m correspondingly, we obtain an explicit expression e for m, denoted as insert(m). In particular, for λ-abstraction λx. m, we have insert(λx. m) = λ α→β x.insert(m) where α → β is a fresh type introduced for λx. m. Theorem D.2 (Soundness). Let m be an implicit such that Γ ⊢ R m : t S . Then for all C ∈ S and for σ, if σ C, then ∅ ; Γσ ⊢ insert(m)@[σ] : tσ.

Proof. By induction on the derivation of Γ ⊢ R m : t S . We proceed by a case analysis of the last rule used in the derivation.

(RECON-CONST): straightforward . (RECON-VAR): straightforward. (RECON-PAIR): consider the following derivation: [START_REF] Castagna | Set-theoretic Foundation of Parametric Polymorphism and Subtyping[END_REF], there exists C1 ∈ S1 and C2 ∈ S2 such that C = C1 ∪ C2. Thus, we have σ C1 and σ C2. By induction, we have ∅ ; Γσ ⊢ insert(m1)@[σ] : t1σ and ∅ ; Γσ ⊢ insert(m2)@[σ] : t2σ. By (pair), we get

(RECON-PROJ): consider the following derivation:

By induction, we have ∅ ; Γσ ⊢ insert(m ′ )@[σ] : t ′ σ. By subsumption, we have ∅ ; Γσ ⊢ insert(m ′ )@[σ] : (α1σ × α2σ). Then by (proj), we get ∅ ; Γσ ⊢ (πi(insert(m ′ )@[σ])) : αiσ, that is ∅ ; Γσ ⊢ insert(πi(m ′ ))@[σ] : αiσ. (RECON-APPL): consider the following derivation: [START_REF] Castagna | Set-theoretic Foundation of Parametric Polymorphism and Subtyping[END_REF], there exists C1 ∈ S1 and C2 ∈ S2 such that C = C1 ∪ C2 ∪ {(t1, ≤ , t2 → α)}. Thus, we have σ C1, σ C2 and t1σ ≤ t2σ → ασ. By induction, we have ∅ ; Γσ ⊢ insert(m1)@[σ] : t1σ and ∅ ; Γσ ⊢ insert(m2)@[σ] : t2σ. By subsumption, we can get ∅ ; Γσ ⊢ insert(m1)@[σ] : t2σ → ασ. Then by (appl), we get ∅ ; Γσ ⊢ (insert(m1)@[σ] insert(m2)@[σ]) : ασ, that is ∅ ; Γσ ⊢ insert(m1 m2)@[σ] : ασ. (RECON-ABSTR): consider the following derivation:

By induction, we have ∅ ; Γσ, (x : ασ) ⊢ insert(m ′ )@[σ] : t ′ σ. By subsumption, we can get ∅ ; Γσ, (x : ασ) ⊢ insert(m ′ )@[σ] : βσ. It is clear that there are no subterms form of e[σj]j∈J in insert(m ′ )@[σ], so insert(m ′ )@[σ] ♯ var(ασ → βσ). Then according to weakening (i.e., Lemma B.8 in the companion paper [START_REF] Castagna | Polymorphic functions with set-theoretic types. Part 1: Syntax, semantics, and evaluation[END_REF]), we have var(ασ → βσ) ; Γσ, (x : ασ) ⊢ insert(m ′ )@[σ] : βσ. Finally, by (abstr), we get ∅ ; Γσ ⊢ (λ α→β

[σ] x. insert(m ′ )) : ασ → βσ, that is ∅ ; Γσ ⊢ insert(λx. m ′ )@[σ] : ασ → βσ. (RECON-CASE): consider the following derivation: Case (i): there exists C0 ∈ S0 such that σ C0, t0σ ≤ 0 and 0 ≤ ασ. By induction, we have ∅ ; Γσ ⊢ insert(m0)@[σ] : t0σ. Since t0σ ≤ 0, we have t0σ ≤ ¬t ′ and t0σ ≤ t ′ . Then applying the rule (case), we have ∅ ; Γσ ⊢ insert(m ′ )@[σ]∈t ′ ? insert(m1)@[σ] : insert(m2)@[σ] : 0, that is, ∅ Γσ ⊢ insert(m ′ ∈t ′ ? m1 : m2)@[σ] : 0. Finally, by subsumption, the result follows. Case (ii): there exists C0 ∈ S0 and C1 ∈ S1 such that σ C0, σ C1 , t0σ ≤ t ′ (t ′ is ground) and t1σ ≤ ασ. By induction, we have ∅ ; Γσ ⊢ insert(m0)@[σ] : t0σ and ∅ ; Γσ ⊢ insert(m1)@[σ] : t1σ. If t0σ ≤ ¬t ′ , then t0σ ≤ t ′ ∧ (¬t ′ ) ≃ 0 (i.e., Case (i)), and thus the result follows by subsumption. Otherwise, we have t0σ ≤ ¬t ′ . Then applying the rule (case), we have Consider the implicit version of map, which can be defined as: µm λf . λℓ . ℓ ǫ nil ? nil : (f (π1ℓ),mf (π2ℓ))

The type inferred for map by the type reconstruction system is α1 → α2 and the generated set S of constraint-sets is:

Then applying the tallying algorithm to the sets, we get the following types for map:

) By replacing type variables that only occur positively by 0 and those only occurring negatively by 1, we obtain

) All the types, except the last two, are useless 15 , as they provide no further information. Thus we deduce the following type for map: 15 These useless types are generated from the fact that 0 → t contains all the functions, or the fact that (0 × t) or (t × 0) is a subtype of any type, or the fact that Case (i) in type-cases is useless in practice.

which is more precise than (α → β) → ([α] → [β]) since it states that the application of map to any function and the empty list returns the empty list.

E. Application to CDuce

We give a rough overview of the modifications that are necessary in order to transpose the algorithms and the results of this work to the implementation of the polymorphic extension of CDuce. In particular, we show how to generalize the static and dynamic semantics of explicit type-case expressions of this work to CDuce's pattern matching expressions. Details about the syntax and semantics of CDuce can be found in [START_REF] Benzaken | CDuce: an XML-friendly general purpose language[END_REF] or, better, in the online documentation available at www.cduce.org.

E.1 Intermediate language

The CDuce compiler includes three different languages (source, typed, and lambda) that are refined one into the other in different passes of the compiler. The first language corresponds to parsed CDuce expressions the last is closer to CDuce bytecode.

The source language is defined in the module ast.ml of the CDuce's source distribution. It is the representation of the source code. The typed language is the result of the type inference performed on the source language and it is defined in the module typed.ml in the source distribution of CDuce. (34) The typed language is similar to the source language. The notable differences are the presence of polymorphic variables x (cf. Part 1, §5.3 [START_REF] Castagna | Polymorphic functions with set-theoretic types. Part 1: Syntax, semantics, and evaluation[END_REF]), the application of substitutions to expressions eσI and the Ξ's associated to patterns in the match expressions. Each Ξi is a mapping from the capture variables of the pattern pi to sets of type variable and will be used to compile away let-polymorphic expression variables (compiling a source expression variable into a monomorphic variable is much less expennsive in terms of run-time performance). Also since this language is the target of type-inference and we do not infer the decorations of lambdas, then λ t p.e stands for λ t ✐ p.e. The typed language is transformed in the intermediate language as result of the compilation step. The evaluation language is defined in the module lambda.ml (35) In the intermediate (or compiled) language, (lazy) type-substitutions "Σ" are now associated to polymorphic variables and to polymorphic lambda expressions. The Ξ annotations present in the patterns of the match expressions are now removed since they were used to determine whether a variable x has to be compiled as xΣ or just as x. The symbol λ is a compiler optimization that is explained at the end of Section 5.3 in Part 1 [START_REF] Castagna | Polymorphic functions with set-theoretic types. Part 1: Syntax, semantics, and evaluation[END_REF]. Notice that we added in lambda abstractions an explicit variable to capture the argument of the function. This is used to compile lambda-expressions with lazy type-substitutions (in particular sel(x, t, Σ) defined right below); in the actual implementation these variables are nameless and compiled by reserving a special slot in the type-environment of closures. Σ ranges over expressions that denote sets of type substitutions.

Σ ::= σI | comp(Σ, Σ ′ ) | sel(x, t, Σ) we use i to denote the identity of these expressions that is the empty set of type substitutions. We use dom(Σ) to denote the domain Σ. It is inductively defined as follows:

dom([σi]i∈I ) = i∈I dom(σi) dom(comp(Σ, Σ ′ )) = dom(Σ) ∪ dom(Σ ′ ) (note: this is a rough approximation) dom(sel(x, t, Σ)) = dom(Σ) Note that dom(i) = ∅. We use var(t) to denote the set of all type variables occurring in the type t.

We use two containment relations. The first s ≤ t is the semantic subtyping relation that states that for all substitutions s is a subtype of t. The second s ⊑∆ t specifies that there exists a substitution for the variables not in ∆ ( ∆ is a set containing all monomorphic variables) such that s ≤ t. We denote the set of all polymorphic variables as ∆.

E.2 Type-directed translation

The CDuce compiler translates one internal language into another. ui ≤ ∨j∈J pj t i 1 = ui ∧ p1 t i j = (ui \ ∨ h<j p h ) ∧ p i j s i j = 0 , ei = ai if t i j ≤ 0 ∆ ′ ; Γ, t i j pj ⊢ I aj : s i j ⊲ e i j otherwise ∆ ; Γ ⊢ I λ ∧ i∈I u i →v i (pj → aj)j∈J : i∈I (ui → vi) ⊲ λ ∧ i∈I u i →v i (pj : ∪iΞ i j → ⊓ie i j σ H i j

)j∈J

∆ ; Γ ⊢ I a1 : t ⊲ e1 ∆ ; Γ ⊢ I a2 : s ⊲ e2 ∆ ; Γ ⊢ I a1a2 : (tσJ ) • (sσI ) ⊲ (e1σJ )(e2σI )