Simplifying and Improving Qualified Types
|
|
- Nigel Lambert
- 5 years ago
- Views:
Transcription
1 Simplifying and Improving Qualified Types Mark P. Jones Department of Computer Science, University of Nottingham University Park, Nottingham NG7 2RD. Abstract Qualified types provide a general framework for constrained type systems, with applications including type class overloading, subtyping and record calculi. This paper presents an extended version of the type inference algorithm used in previous work, that can take account of the satisfiability of constraints to obtain more accurate principal types. The new algorithm is obtained by adding two new rules, one for simplification and one for improvement of constraint sets. In particular, it permits a better treatment of the previously troublesome multiple parameter extensions of Haskell type classes, generalizing the system of parametric type classes proposed by Chen, Hudak and Odersky. 1 Introduction Qualified types provide a general framework for constrained type systems; typical applications include type class overloading, subtyping and record calculi. In previous work, we have shown how the standard treatment of ML style polymorphism can be adapted to support qualified types. In particular, any well-typed program has a principal type that can be calculated by an extended version of Milner s type inference algorithm. This is useful both for describing the set of types that can be assigned to a term and for detecting possible semantic ambiguities. Unfortunately, while technically correct, the principal types produced by our algorithm do not take account of the satisfiability of constraints. As a result, they are sometimes more complicated and less accurate than we might hope. Even if the additional complexity were not an issue, this can sometimes cause perfectly reasonable programs to be rejected when the principal type suggests, wrongly, that the term does not have a well-defined semantics. In other cases, the inferred types are too liberal, including unsatisfiable constraints and delaying the detection of type errors. This paper shows how these problems can be avoided by using a notion of principal satisfiable types and extending the type inference algorithm with two new rules, one dealing with simplification, the other with improvement. Our approach is flexible enough to allow variations between different applications of qualified types, offering better principal types without compromising the decidability of type inference. In addition to other applications, the new algorithm permits a better treatment for the previously troublesome multiple parameter extensions of Haskell type classes. In particular, we show how improvement can support a form of parametric type classes [1]. We start, in Section 2, with an overview of the system of qualified types used in earlier work, including examples of predicate systems, a description of the type system and an outline of the type inference algorithm. Section 3 describes the use of simplification, allowing the constraint set included in the type of an expression to be replaced by an equivalent, but simpler, set of constraints. In Section 4, we introduce the concept of improvement which is the major contribution of this paper, using information about satisfiability of constraints to refine the inferred types. This requires a modification to our treatment of type inference, shifting attention to satisfiable typings and a satisfiability ordering between type schemes in Section 5. The proofs of soundness and completeness properties for a type inference algorithm that uses simplification and improvement are discussed in Section 6; detailed proofs of new results are provided elsewhere [15]. We conclude with a discussion on the use of our new framework in Section 7. 2 A brief overview of qualified types To describe the contributions of this paper we need to begin with a brief description of the framework of qualified types on which it builds. We make no attempt to repeat the full details of earlier presentations [11, 10]. 2.1 Predicates The key idea motivating the use of qualified types is the ability to include predicates in the type of a term, capturing restrictions on the ways that it can be used. The properties of predicates themselves are described using an entailment relation, denoted by the symbol. If P and Q are finite sets of predicates, then the assertion that P Q means that the predicates in Q hold, whenever the predicates in P are satisfied. The only assumptions that we make about the predicate entailment relation are that it is transitive, closed under substitutions, and such that P Q whenever Q is a subset of P. Simple examples of single predicates that are useful in practical applications are illustrated in Figure 1. In some cases, we have taken the liberty of using a slightly different syntax
2 Predicate Interpretation t Eq Values of type t can be tested for equality using the == operator. This usually includes all types, except those with functional components [21, 7]. t Num t is a numeric type, for example, the type of integers, or floating point numbers, and elements of type t can be manipulated using standard arithmetic operators, for example, + for addition and for multiplication [21, 7]. t Collect(s) Values of type t can be used to represent collections of values of type s [1]. t Dual s Values of types t and s represent the elements of dual lattices [9]. s t s is a subtype of t; in practice, this usually means that values of type s can be treated as values of type t by applying a suitable coercion [16, 17, 4, 3, 19]. r has l :t r is a record type containing an field labelled l of type t [6]. r lacks l r is a record type, not including a field labelled l [6]. r 1 #r 2 The record types r 1 and r 2 do not have any fields in common [5]. Figure 1: Examples of individual predicates and their informal interpretation from earlier presentations, in the hope that this will make the interpretation of some predicates a little more obvious. 2.2 OML Core-ML with overloading Working towards an extension of core-ml that supports qualified types, we adopt a structured language of types specified by the grammar: τ ::= t type variables τ τ function types... other constructed types ρ ::= P τ qualified types σ ::= T.ρ type schemes Here, t ranges over a given set of type variables and P and T range over finite sets of predicates and finite sets of type variables respectively. The set of type variables appearing (free) in an expression X is denoted TV (X ) and is defined in the obvious way. For programs, we use the term language of core-ml: E ::= x variable EF application λx.e abstraction let x = E in F local definition For the purposes of this work, we are only interested in terms that can be assigned a type using the rules in Figure 2. These rules use judgements of the form P A E : σ where P is a set of predicates and A is a type assignment, i.e. a mapping from term variables to types. Much of the notation used here is standard, as indeed are most of the rules. For example, the notation A x refers to the type assignment obtained from A by deleting the type assigned to x, if any. Only ( I ) and ( E), moving global constraints in to, or out of, the type of an object, and the ( I ) rule for polymorphic generalization, actually involve the predicate set P. We refer, collectively, to the type, term and typing rules given above as OML, a mnemonic for Overloaded ML. 2.3 Type inference for OML An important property of OML is the existence of an algorithm for calculating principal typings for a given term. More precisely, there is an effective algorithm, taking a term E and a type assignment A as its input, for calculating the most general type that can be assigned to E, given the assumptions in A. To describe what it means for one type to be more general than another, we define an ordering between constrained type schemes, i.e. pairs of the form (P σ) where σ is a type scheme and P is a set of predicates. We start by defining the set of generic instances of a constrained type scheme: [[P α i.p τ]] = { Q [ν i /α i ]τ ν i Type, Q P, [ν i /α i ]P }. Using this definition, the required ordering between constrained type schemes is specified by law: (P σ) (P σ ) [[P σ]] [[P σ ]]. In other words, σ σ if and only if every generic instance of σ is a generic instance of σ. It follows immediately from the form of the definition that the ordering is reflexive and transitive. Furthermore, it is reasonably easy to show that the ordering is preserved by substitution, i.e. that S(P σ) S(P σ ), whenever (P σ) (P σ ). This is important because it indicates that the ordering on type schemes is compatible with our notion of polymorphism, allowing free type variables to be freely instantiated with arbitrary types. The type inference algorithm itself is described by the rules in Figure 3. This presentation, as in previous descriptions of qualified types, follows Rémy [18], using judgements of the form Q TA W E : ν where A and E are the type assignment and expression provided as inputs to the algorithm, and Q, T and ν are a predicate set, substitution and type, respectively, produced as its results. The notation Gen(A, ρ) used in the rule (let) W indicates the generalization of ρ with respect to A, defined as a i.ρ where {a i } is the set of type variables TV (ρ) \ TV (A). As demonstrated in previous work, the results of the algorithm can be used to construct a principal type scheme, η, such that: P A E : σ (P σ) η. Assuming, as is often the case for top-level definitions, that A does not include any free type variables, then the principal type is just: η = Gen(A, Q ν) = ( a i.q ν), where {a i } is the set of type variables appearing free in (Q ν). Note that it is also possible for the type inference algorithm to fail, either because E contains a free variable that is not bound in A, or because the calculation of a most general
3 (var) (x :σ) A P A x : σ ( E) P A E : Q ρ P Q P A E : ρ ( E) P A E : τ τ P A F : τ P A EF : τ ( I ) P, Q A E : ρ P A E : Q ρ ( I ) P A x, x :τ E : τ P A λx.e : τ τ ( E) P A E : α.σ P A E : [τ/α]σ (let) P A E : σ Q A x, x :σ F : τ P, Q A (let x = E in F ) : τ ( I ) P A E : σ α TV (A) TV (P) P A E : α.σ Figure 2: Typing rules for OML. unifier, described by the notation τ U τ, fails as a result of a mismatch between the expected and actual type of a function argument. In this case, the completeness property of the type inference algorithm guarantees that there are, in fact, no derivable typings of the form P A E : σ. 3 Simplification In this section, we will show how inferred types can be simplified by replacing one predicate set with another, equivalent set of constraints. This is not a new idea; similar techniques are already used in other theoretical work, and in the implementations of systems like Haskell [7] and Gofer [14]. One of the advantages of the framework used in this paper is that it allows us to view simplification independently of other aspects of the type system, revealing opportunities for specific design decisions that are hidden in other presentations of constrained type inference. For convenience, we write P Q to indicate the equivalence of predicate sets P and Q, i.e. that P Q and Q P. It is a straightforward exercise to show that, if P Q, then: [[ t i.p τ]] [[ t i.q τ]], and hence that, if P Q, then ( t i.p τ) and ( t i.q τ) are equivalent with respect to the ordering on type schemes. Applications of simplification in Haskell include: Constant predicates. The Int type is an instance of the Eq class and hence { Int Eq } is equivalent to the empty predicate set, {}. Superclass hierarchies. The Eq class is defined as a superclass of Ord; static checks are used to ensure that Ord Eq and hence a predicate set of the form { τ Eq, τ Ord } can be simplified to just { τ Ord }. Context reduction. The definition of equality on lists relies on the existence of a definition of equality on the individual elements of the list. This corresponds to an equivalence: { t Eq } { [t] Eq }. Rules like this can be used to ensure that all constraints in inferred types are of the form t C (t is a type variable), as required by Haskell. Simplification is also useful in other applications of qualified types. Simplification may be used at any stage during the typing process. We can extend the algorithm in Figure 3 to allow this by adding the rule (Simp): Q TA W E : ν P Q P TA W E : ν This gives a non-deterministic type inference algorithm: it is possible to obtain distinct principal types that are not equal up to renaming of bound variables. Fortunately, since these types are equivalent under the ordering introduced in Section 2.3, the addition of (Simp) still yields a sound algorithm that calculates principal type schemes for OML programs. By adopting a non-deterministic algorithm, we have the flexibility to allow designers of applications of qualified types to refine the algorithm, choosing to use simplification only under certain circumstances or at specific points during type checking. We should also comment that, although we have specified what it means for two predicate sets to be equivalent, we will not attempt to formalize what it means to say that one is simpler than another. There are some obvious measures of complexity that could be used, for example, the number of predicates or the size of the type expressions involved. However, we believe that these issues are best dealt with in the design of specific applications. More directly, while we use a general and symmetric notion of simplification that allows any equivalent predicate set Q to be used in place of P, we would expect that, in a real implementation, Q will actually be chosen as a simplified version of P in some appropriate manner. 4 Improvement A second method for inferring more accurate principal types, and the most important contribution of this paper, is based on the concept of improvement. Although some special cases of this idea have been used in other systems, we are not aware of any previous work that has either identified the notion of improvement as an independent concept, or developed these ideas in the general framework described below. 4.1 Improving records The central idea is to use information about the satisfiability of predicate sets to simplify inferred types. As a first example, consider a language with a system of records, using a function: (.l) :: r. t.(r has l :t) r t
4 (var) W (x : α i.p τ) A β i new [β i /α i ]P A W x : [β i /α i ]τ P TA W E : τ Q T TA W F : τ T τ U τ α α new ( E) W U (T P, Q) UT TA W EF : U α P T (A x, x :α) W E : τ α new ( I ) W P TA W λx.e : T α τ (let) W P TA W E : τ P T (TA x, x :σ) W F : τ σ = Gen(TA, P τ) P T TA W (let x = E in F ) : τ Figure 3: Type inference algorithm W. to describe the selection of a field l of type t from a record of type r. Following conventional notation, we treat the expression e.l as a sugared version of (.l) e. Now consider the function f = λr.(r.l, r.l) whose principal type, according to the algorithm in Section 2.3, is: r. a. b.(r has l :a, r has l :b) r (a, b). However, for any particular record type r, the types assigned to the variables a and b must be identical since they both correspond to the same field in r. It would therefore seem quite reasonable to treat f as having a principal satisfiable type scheme: r. a.(r has l :a) r (a, a). To capture the essence of this example in a more general setting, we introduce the following notation for describing the satisfiable instances of a given predicate set P with respect to a predicate set : P P0 = { SP S Subst, SP }. The predicate set used here is arbitrary, although we will often use = and we will always assume that TV ( ) =. In practice, the choice of plays a relatively small part in the following and we will often omit the subscript, writing just P to avoid unnecessary distraction. It is easy to show that SP P, for any substitution S, and any predicate set P. The reverse inclusion, P SP, does not always hold, but is more interesting because it tells us that we can apply the substitution S to P without changing its satisfiable instances. In particular, taking S as the substitution [a/b], the argument about the predicates for record types given above is captured by the equality: r has l :a = r has l :a, r has l :b. In this case, we will say that the substitution [a/b] improves the predicate set {r has l :a, r has l :b}. More generally, we write S improves P if P = SP and the only variables involved in S that do not appear in P are new variables, similar to those introduced by the type inference algorithm in Figure 3. To make use of improvement during type inference, we extend the type inference algorithm with the rule (Imp): Q TA W E : ν T improves Q T Q T TA W E : T ν To get the most benefit from this, we would obviously prefer to use substitutions T that give, in some sense, the best possible improvement. However, while this is desirable, we do not make it a requirement of the work described here. This is important because the definition of general predicate systems does not guarantee the existence of optimal improvements, or of computable algorithms for calculating them. Instead, we provide a general framework that allows us to compromise between decidability and improvement. In the simplest case, we can use the identity substitution id as an improving substitution, which satisfies id improves P for all predicate sets P. Of course, this just gives the same results as the previous version of the type inference algorithm, without improvement 1. In practice, the typing algorithm for a language based on the ideas presented here might be parameterized by the choice of an improving function, impr, such that (impr P) improves P for any predicate set P. The argument above shows that there is always at least one possible choice for an improving function, namely impr(p) = id. We will see that it is also possible to arrange for an improving function to fail, thereby causing the type inference algorithm to fail, if it is applied to an unsatisfiable predicate set, i.e. a predicate set P such that P P0 =. This can be used to implement a type checker that produces only satisfiable typing judgements, and fails if and only if there are no satisfiable typings. Of course, this behaviour would not be appropriate for a system in which tests of the form P P0 = are not decidable. Once again, our framework allows the language designer to control these aspects of the type inference algorithm by choosing a suitable improving function. 4.2 Improving subtyping To see why it may be necessary to introduce new variables in an improving substitution, consider a system of subtyping using predicates of the form τ τ to indicate that τ is a subtype of τ and with an entailment relation that is fully determined by the following rules: P τ τ P Q P Q 1 Pun intended! P τ ν P ν µ P τ µ P τ τ P ν ν P (τ ν) (τ ν )
5 Using an implicit coercion, the function g = λf.λx.1 + f x has principal type: a. b.(a (b Int)) a b Int. Taking = {Int Float}, i.e. assuming that the only primitive coercion is from the type Int of integers to the type Float of floating point numbers, we can use an improving substitution [(c d)/a] since: a (b Int) = (c d) (b Int). In fact, we can obtain a further improvement by noticing that this requires d Int, which is only possible if d = Int. Hence the improved type for g becomes: b. c.((c Int) (b Int)) (c Int) b Int. Now, as is often the case, improvement exposes new opportunities for simplification, and we can further refine the type of g to: b. c.(b c) (c Int) b Int. Note that improvement can be considered as a generalization of the use of Mitchell s MATCH algorithm [16, 17]. 4.3 Improving type classes In this section, we will show how improvement can be used to support the use of type classes, concentrating in particular on the proposals by Chen, Hudak and Odersky [1] for parametric type classes. Several researchers, including this author, have experimented with systems of multiple parameter type classes. Thinking of standard type classes as sets of types, the simplest interpretation of a multiple parameter class is as a set of tuples of types, corresponding to a relation on types. For example, a two parameter class, Dual, can be used to describe duality between lattices [9]. Unfortunately, practical experience with multiple parameter type classes in Gofer [8] suggests that the standard mechanisms for defining classes and instances in Haskell are often too weak to define useful relations between types 2. To illustrate the kind of problems that can occur, suppose that we use predicates of the form c Collect(a) to indicate that values of type c can be used to represent collections of values of type a. A simple class for operations on collections can be defined as follows: class c Collect(a) where empty :: c insert :: a c c member :: a c Bool The empty value represents an empty collection, while the insert and member functions might be used to add an element, or to test whether a particular element is included in a collection. There are a number of ways to implement collections. One of the simplest ways is to use a list, assuming that the values it holds can be tested for equality so that we can implement the membership test: instance (a Eq) [a] Collect(a) where 2 Interestingly enough, these problems do not seem to occur for many useful examples involving multiple parameter constructor classes [13]. A more efficient implementation might be obtained using binary search trees if we assume that there is an ordering on the elements held in a collection, captured by the type class Ord in the following definition: data BST a = Empty Fork a (BST a) (BST a) instance (a Ord) (BST a Collect(a)) where On the surface, these definitions seem quite reasonable, but we soon run into difficulty if we try to use them. One of the first problems is that the type of the empty value is a. c.(c Collect(a)) c, which is ambiguous in the sense that a type variable a appears on the left of the symbol, but is not mentioned on the right. As a result, there is no general way to determine the intended value of type a from the context in which empty is used. In general, it is not possible to use any term with an ambiguous principal type if we hope to provide a well-defined semantics for the language [10, 12]. Another problem is that the types assigned to member and insert are more general than we might expect. For example, it is possible to define collections that contain different types of elements and to define functions like: intorbool :: c.(c Collect(Int), c Collect(Bool)) c Bool intorbool c = member 1 c member True c It is certainly possible that such examples might be useful in some applications. However, in many cases, we would prefer to restrict collections to hold values of a single type only, and to treat function definitions like this as type errors. The problems described above can be avoided by using parametric type classes [1]. This allows us to use the same class and instance declarations as above, but to extend the compiler with additional static checks to ensure that, if { τ Collect(ν), τ Collect(ν ) }, then ν = ν. In effect, this means that, for any satisfiable instance of a predicate c Collect(a), the choice of type a is uniquely determined by the choice of c. Note that this can also be captured by an improving function impr such that: ν U ν impr {τ Collect(ν), τ Collect(ν )} = U If no unifier exists, then the predicate set is unsatisfiable, and the improving function may fail. Other useful rules for improvement can be derived from this general rule. For example, according to the instance declarations given above, a predicate of the form [ν] Collect(ν ) can only be satisfied if ν = ν, so we can define: ν U ν impr {[ν] Collect(ν )} = U Parametric type classes are a good way of avoiding the problems with ordinary multiple parameter type classes that were sketched above. Since the choice of a in c Collect(a) is uniquely determined by the value of c, there is no need to treat empty as having an ambiguous type. In addition, the restrictions on instances of parametric type classes are exactly the conditions that we need to ensure that the definition of intorbool will be treated as a type error. Improvement is particularly important for Haskell since it permits, for the first time, a useful treatment of multiple parameter type classes that generalizes the use of parametric type classes. At the same time, it is fully compatible with the Haskell type system, including context reduction, and with the use of constructor classes.
6 5 Taking account of satisfiability Since the types obtained by improvement in the examples above are obviously instances of the original principal types, it is no surprise to find that our extended type inference algorithm is sound, i.e. that the typings it produces are derivable in the original typing rules given in Figure 2. Theorem 1 If Q TA W E : ν, then Q TA E : ν. On the other hand, the new algorithm is certainly not complete. Indeed, it is not even well-defined with respect to the natural equivalence on type schemes induced by the ordering. For example, the two type schemes for the function f in Section 4.1, either of which could be produced by the new algorithm, are: σ 1 = r. a.(r has l :a) r (a, a), σ 2 = r. a. b.(r has l :a, r has l :b) r (a, b). It is easy to show that σ 1 σ 2, but these types are not equivalent because σ 2 σ 1. Hence the new type inference algorithm may give a result type σ 1 that is not principal. Even worse, there are terms that can be typed using the original rules in Figure 2, but for which the type inference algorithm may fail to produce a typing. For example, consider the expression: λr.let (x, y) = f r in (x + 1, not y). Using the type scheme σ 2 for f, we can instantiate the type variables a and b to Int and Bool, respectively, to obtain a typing for this term. However, using the type scheme σ 1, the type inference algorithm fails because the types Int and Bool do not match. The key to solving this problem is to notice that, although we can obtain a typing for this term using type scheme σ 2, the corresponding predicate set, {r has l : Int, r has l : Bool}, is not satisfiable. We will see that the problems described above can be avoided by: Proving completeness of the algorithm with respect to a weaker ordering that identifies type schemes with the same set of satisfiable instances: Just as the original ordering on type schemes was defined in terms of the set of generic instances of a type scheme, we will define the new ordering in terms of the generic satisfiable instances of a type scheme with respect to a predicate set. The set of generic satisfiable instances of a type scheme is defined by: [[P α i.p τ]] sat = { [ν i /α i ]τ ν i Type, P, [ν i /α i ]P }. The satisfiability ordering, again with respect to, can now be defined using: (P σ) sat (P σ ) [[P σ]] sat [[P σ ]] sat. Clearly, sat is both reflexive and transitive. It is also quite easy to show that it is weaker than, i.e. that: (P σ) (P σ ) (P σ) sat (P σ ). On the other hand, unlike, the satisfiability ordering is not preserved by substitution 3. 3 As a counter example, consider a predicate a C for which the only satisfiable instance is Int C. Now consider the qualified types η i = (a i C ) a i, for i = 1, 2, and let S = [Int/a 1 ]. Then [η 1 ] sat = = [η 2 ] sat, and hence η 1 sat η 2, but [Sη 1 ] sat = {Int} while [Sη 2 ] sat = [η 2 ] sat =, so Sη 1 Sη 2. Restricting our attention to satisfiable typings: A typing of the form P A E : σ is of no practical use if the predicates in P do not hold or if there is no way to satisfy the predicates involved in σ. We can capture these conditions formally by defining: sat (P σ) [[P σ]] sat. The following properties of this relationship between predicate sets and type schemes are easily established and show that this notion of satisfiability is well-behaved with respect to polymorphism (i.e. instantiating free variables), entailment and ordering: If sat (P σ), then S sat S(P σ) for any substitution S. If sat (P σ) and Q 0, then Q 0 sat (P σ). If sat (P σ ) and (P σ ) sat (P σ), then sat (P σ). There is one further problem that occurs when an unused let-bound variable is assigned an unsatisfiable type scheme. As an illustration, consider the following type assignment and predicate set: A = { f : α.α C α α, z : α.α D α } P = { a C, a D } where C and D are disjoint singletons, say C = { Int } and D = { Bool, }, and hence: [Int/α] improves {α C } and [Bool/α] improves {α D}. Using the original typing rules for OML, we can construct a derivation of the form: (P, P) A f : a a (P, P) A z : a (P, P) A f z : a P A f z : σ P A, x :σ F : τ P A let x = f z in F : τ where σ = ( a.(a C, a D) a). Clearly σ is not satisfiable, but, if the bound variable x does not appear free in F, then there is no reason for these unsatisfiable constraints to be reflected by the predicates in P. However, in the type inference algorithm, using improvement immediately after the introduction of the variables f and z would produce typings of the form: Q A f : Int Int and Q A z : Bool and the algorithm will fail to infer a type for the expression f z. The problem here is that, since x FV (F ), the use of generalization in the typing rule for let-expressions allows us to hide, and then discard unsatisfiable constraints. We will describe an expression of the form let x = E in F where x FV (F ) as a redundant let-binding. Such bindings serve no practical purpose because they can be replaced by the corresponding expression (λx.f )E without a change in either semantics or typeability. With this observation, it is reasonable to restrict our attention to terms with no redundant let-bindings. Obviously, if this property holds for a given term E, then it also holds for all subterms of E, a fact that can be used implicitly in proofs by induction. Given the definitions above, we can now state the main completeness result for a type inference algorithm that supports both simplification and improvement rules:
7 Completeness: Suppose that P SA E : σ. Then Q TA W E : ν and there is a substitution R such that S RT and (P σ) RGen(TA, Q ν). Completeness s : If P A E : σ, then there is a set of predicates P and a type τ such that P A s E :τ and (P σ) Gen(A, P τ). Soundness s : If P A s E : τ, then P A E : τ. Completeness W : If P SA s E : τ, then Q TA W E : ν and there is a substitution R such that S RT, τ = Rν and P RQ. s Soundness W : If P TA W E : τ, then P TA s E : τ. W Soundness: If P TA W E : τ, then P A E : τ. Figure 4: A summary of the original soundness and completeness results. Theorem 2 Suppose that P A E : σ and sat (P σ) where E is a term with no redundant let-bindings and TV (A) =. Then the type inference algorithm for E in A will not fail, and, for any Q and ν such that Q A W E : ν, we have: (P σ) sat Gen(A, Q ν). This result indicates that, if a term E has any satisfiable typings for a set A of typing assumptions, then there is a principal type η = Gen(A, Q ν) which is more general than every satisfiable typing for E in A. In fact, the principal type is itself a satisfiable typing for E in A: Satisfiability follows directly from the fact that it is an upper bound of a non-empty set of satisfiable constrained type schemes. To see that η is a typing for E in A, we can use the soundness result above (Theorem 1) to show that Q A E : ν, and then use ( I ) and ( I ) to obtain a derivation A E : η. It is also possible to state a more general version of the completeness theorem without the requirement that TV (A) =. However, in practice, this special case is usually of most interest, corresponding to the process of calculating the type for a top-level definition in a Haskell or ML program. 6 Proof of soundness and completeness The main purpose of this section is to prove the soundness and completeness results stated in the previous section as Theorem 1 and Theorem 2, respectively. This is a complicated task that requires careful management and structuring. Fortunately, we can reduce the amount of work involved by building on the results of previous work. The diagram in Figure 4 summarizes the main results for the original system of qualified types [11, 10], describing the relationship between typing judgements in three different systems: The original typing rules for OML (Figure 2), described by judgements using the symbol. The type inference algorithm (Figure 3), described by judgements using the W symbol. A collection of syntax-directed typing rules described by judgements using the s symbol. This system provides a convenient stepping stone between the original typing rules and the type inference algorithm, and will be described in more detail below. Following convention, the results in the top portion of Figure 4 are described as completeness properties, while those in the lower portion are referred to as soundness properties. In each case, the result linking the and W systems can be obtained from the corresponding properties involving s. The original typing rules for OML are not suitable for type inference: there are many different ways that the rules can be applied to a given term, but it is not clear which, if any, will lead to a principal type. In earlier work, following standard techniques [2], we avoided these problems by defining a syntax-directed system and proving its equivalence with the original type system using the theorems labelled Soundness s and Completeness s in Figure 4. The most important property of the syntax-directed system is that the structure of every typing derivation is uniquely determined by the syntactic structure of the term involved. The typing rules for the syntax-directed system are given in Figure 5 using judgements of the form P A s E : τ. Several useful properties of the syntax-directed system have been established [11, 10], including: If P A s E :τ and S is a substitution, then SP SA s E : Sτ. If P A s E : τ and Q P, then Q A s E : τ. If P A s E : τ and A A, then P A s E : τ. For the purposes of the work described in this paper, the first two properties are important because they are exactly what we need to establish soundness of rules (Imp) and (Simp), respectively, in the proof of Theorem 1 (The remaining cases are the same as in the original proof of Soundness W ). The expression A A in the third property indicates that the two type assignments A and A have the same domain and that A(x) A (x) for each variable x bound in A. In the following, we will use the obvious counterpart to describe when one type assignment A is more general than another A
8 (var) s (x :σ) A (P τ) σ P A s x : τ ( I ) s P A x, x :τ s E : τ P A s λx.e : τ τ ( E) s P A s E : τ τ P A s F : τ P A s EF : τ (let) s P A s E : τ P A x, x :σ s F : τ σ = Gen(A, P τ) P A s (let x = E in F ) : τ Figure 5: Syntax-directed inference system. with respect to the satisfiability ordering, written A sat A. The third property plays an important role in the proof of Completeness W, i.e. for the original system of qualified types [10]. Unfortunately, the corresponding result with replaced by sat does not hold. A simple counterexample can be obtained from the example in Section 5, since (P, P) A s f z : a, and A sat A = { f :(Int Int), z :Bool }, but there is no derivable typing for the expression f z using the assignment A. We avoid this problem in the completeness theorem below by including an assumption of the form A sat SA as an extra hypothesis. A similar technique is used in Smith s thesis [19]. In the remaining part of this section, we will describe a replacement for the Completeness W result in Figure 4 that allows the use of the rules (Simp) and (Imp) at arbitrary points during type inference. Combined with Completeness s, we will show how this can be used to establish Theorem 2, an analogue of the Completeness result at the top of Figure 4. Our first task is to justify the informal comments about terms with no redundant let-bindings in Section 5. Using the syntax-directed typing rules, the following theorem shows that, the class constraints for a variable x appearing free in an expression E will be reflected by the constraints P on the use of E itself: Proposition 3 Suppose that P A s E : τ, x FV (E), A(x) = ( α i.q ν), and that E has no redundant letbindings. Then there are types τ i such that P [τ i /α i ]Q. In particular, if we have a satisfiable syntax-directed typing for a term E with respect to some set of assumptions A, and if the variable x appears free in E, then the type assigned to x in A must also be satisfiable: Corollary 4 Suppose that P A x, x : Gen(A, Q ν) s E : τ, x FV (E), sat Gen(A, P τ), and that E has no redundant let-bindings. Then: sat Gen(A, Q ν). Working towards a completeness result for the type inference algorithm with respect to the syntax-directed type system, suppose that we have a derivation P A s E : τ. Our goal is to prove that: The type inference algorithm will not fail to find a type for E in A. Since the algorithm may fail if E does not have any satisfiable typings, it will be necessary to restrict our completeness result to satisfiable syntaxdirected derivations, i.e. to derivations P A s E : τ such that sat Gen(A, P τ). If the type inference algorithm produces a typing Q TA W E : ν, then the corresponding type scheme Gen(TA, Q ν) is more general than the type assigned to E in the syntax-directed system, i.e. we want to show that: Gen(A, P τ) sat Gen(TA, Q ν). In fact, to carry out the required proof, it is necessary to generalize the hypotheses a little, allowing the use of distinct type assignments, A in the original syntaxdirected typing, and A in the type inference algorithm, related by A sat SA for some substitution S. Motivated in part by these comments, we use the following theorem to express the completeness of the type inference algorithm with respect to the syntax-directed rules, and the satisfiability ordering, sat : Theorem 5 Suppose that P A s E : τ, sat Gen(A, P τ), A sat SA, and that E does not contain any redundant let-bindings. Then the type inference algorithm will not fail, and for every Q TA W E : ν, there is a substitution R such that RT S and: Gen(A, P τ) sat RGen(TA, Q ν). The proof of this theorem is a little complex; full details are given elsewhere [15]. However, with this result in hand, the proof of Theorem 2 is straightforward. Suppose that P A E : σ and sat (P σ) where E is a term with no redundant let-bindings and TV (A) =. By Completeness s, we know that P A s E : τ for some P and τ such that: (P σ) Gen(A, P τ ). From the properties of sat, it follows that (P σ) sat Gen(A, P τ ), and hence, since sat (P σ), that sat Gen(A, P τ ). Since A sat A, we can use Theorem 5 to show that the type inference algorithm will not fail and that, for each Q TA W E : ν, there is a substitution R such that Gen(A, P τ ) sat RGen(TA, Q ν). Since TV (A) =, we know that Gen(TA, Q ν) has no free variables and that TA = A. Combining the two sat orderings above, we obtain (P σ) sat Gen(A, Q ν) as required. 7 Discussion The ideas described in this paper provide a general and modular framework for the design of constrained type systems, taking advantage of information about satisfiability of constraints to infer more accurate and informative principal types. The design of specific applications of our framework starts with the choice of a system of predicates and an entailment relation, as described in Section 2.1. Without any further
9 work, the original type inference algorithm presented in Figure 3 can be used to calculate principal typings for the corresponding system of qualified types. Extending the algorithm with rules for simplification and improvement leads to a non-deterministic type inference algorithm. This allows us to choose how the rules will be combined in particular ways to provide a deterministic algorithm for use in practical implementations. For a more algorithmic flavour, we would normally expect the implementation of simplification and improvement to be described by (deterministic) functions, rather than the more general and improves relations used by the presentations in Sections 3 and 4, respectively: A simplifying function, simp, mapping predicate sets P to appropriate simplified versions, simp P, might can be used to implement simplification. The only condition that a simplifying function must satisfy is that P (simp P), for all predicate sets P. In this setting, the inference rule (Simp) introduced in Section 3 might be replaced by: Q TA W E : ν P = simp Q P TA W E : ν For any predicate system, the identity function specified by simp P = P can be used as a simplifying function. However, more interesting, and more useful functions can be used in specific applications. In a similar way, an improving function, impr, mapping sets of predicates to suitable improving substitutions, can be used to implement improvement, as described in Section 4.1. The correctness of an improving function can be specified by the requirement that (impr P) improves P, for all predicate sets P, and the (Imp) inference rule introduced in Section 4 can be rewritten to use an improving function: Q TA W E : ν T = impr Q T Q T TA W E : T ν The trivial improving function, impr P = id can be used with any system of predicates, but it is often possible to find more useful definitions. Note that it is possible to arrange for simplifying or improving functions to fail if they are applied to an unsatisfiable predicate set, causing the type inference algorithm to fail as a result. However, while this may be useful in some applications, it is not required; in the general case, testing for satisfiability of a predicate set is undecidable and we would not be able to guarantee termination of the type inference algorithm (see the work of Volpano and Smith [20], for example). For similar reasons, while we expect the results of simplifying and improving functions to satisfy certain correctness conditions, we do not insist that they are optimal ; in the general case, there may not be any effective way to find such optimal solutions. Our approach is to leave the task of finding suitable simplifying and improving functions to the designer of specific applications of qualified types. In this way, designers retain control over the balance between making good use of simplification and improvement, and ensuring that type inference remains tractable. This is in contrast to earlier work, for example, by Smith [19], where full tests for satisfiability of predicate sets are needed and strong restrictions on the definition of predicate entailments are needed to guarantee a decidable type inference process. One of the most obvious places to use simplification and improvement is immediately before generalizing the type of a let-bound variable. For example, using the rules above, we can derive the following rule for calculating the type of a let-expression: P TA W E : ν T = impr P Q = simp (T P) σ = Gen(T TA, Q T ν) P T (T TA x, x :σ) W F : τ P T T TA W (let x = E in F ) : τ Of course, we could have started out with this rule at the very beginning. However, our approach seems much more attractive and modular since it allows us to view the typing of let-expressions and the treatment of simplification and improvement as independent concerns and to combine them in ways that are not captured by the rule above. In their current state, the ideas presented in this paper are of most use to language designers, not to programmers. For example, the design of a type inference algorithm for a language with parametric type classes can be based on the framework and algorithms presented here. It would also be interesting to explore more ambitious language designs that provide the programmer with the ability to define and extend simplifying and improving functions. Some first steps in this direction have been made [15]. In the meantime, the work described here provides simple correctness criteria for simplifying and improving functions which can be useful in the construction of such functions for specific applications of qualified types. For example, the task of simplifying predicate sets containing subtyping constraints has been studied in some depth by several researchers [16, 17, 4, 3, 19]. This paper does not subsume the results of their work. Rather, it provides a general framework to which their results may be applied in the design of type systems combining polymorphism and subtyping. Acknowledgements Much of this work was carried out while the author was a member of the Department of Computer Science, Yale University, and was supported in part by a grant from ARPA, contract number N J It is a pleasure to thank Kung Chen for useful discussions about the ideas presented in this paper, and for helpful insights into his work on parametric type classes. The concept of principal satisfiable type schemes was originally introduced in [10, Chapter 6]. At that time, we conjectured that every term with a satisfiable typing could be assigned a principal satisfiable typing, a fact which we have, finally, had the opportunity to prove! References [1] K. Chen, P. Hudak, and M. Odersky. Parametric type classes (extended abstract). In ACM conference on LISP and Functional Programming, San Francisco, CA, June [2] D. Clément, J. Despeyroux, T. Despeyroux, and G. Kahn. A simple applicative language: Mini-ML.
10 In ACM symposium on LISP and Functional Programming, Cambridge, Massachusetts, August [3] Y.-C. Fuh and P. Mishra. Polymorphic subtype inference: Closing the theory-practice gap. In Proceedings of TAPSOFT 89, New York, Springer-Verlag. Lecture Notes in Computer Science, 352. [4] Y.-C. Fuh and P. Mishra. Type inference with subtypes. Theoretical computer science, 73, [5] Robert Harper and Benjamin Pierce. A record calculus based on symmetric concatenation. In Conference record of the Eighteenth Annual ACM Symposium on Principles of Programming Languages, Orlando, FL, January [6] R.W. Harper and B.C. Pierce. Extensible records without subsumption. Technical report CMU-CS , Carnegie Mellon University, School of computer science, February [7] P. Hudak, S. Peyton Jones, and P. Wadler (editors). Report on the Programming Language Haskell, A Nonstrict Purely Functional Language (Version 1.2). ACM SIGPLAN Notices, 27(5), May [8] Mark P. Jones. Introduction to Gofer 2.20, September Available by anonymous ftp as part of the standard Gofer distribution. [9] Mark P. Jones. Computing with lattices: An application of type classes. Journal of Functional Programming, 2(4), October [10] Mark P. Jones. Qualified Types: Theory and Practice. PhD thesis, Programming Research Group, Oxford University Computing Laboratory, July Published by Cambridge University Press, November [11] Mark P. Jones. A theory of qualified types. In ESOP 92: European Symposium on Programming, Rennes, France, New York, February Springer-Verlag. Lecture Notes in Computer Science, 582. [12] Mark P. Jones. Coherence for qualified types. Research Report YALEU/DCS/RR-989, Yale University, New Haven, Connecticut, USA, September [13] Mark P. Jones. A system of constructor classes: overloading and implicit higher-order polymorphism. In FPCA 93: Conference on Functional Programming Languages and Computer Architecture, Copenhagen, Denmark, New York, June ACM Press. [14] Mark P. Jones. The implementation of the Gofer functional programming system. Research Report YALEU/DCS/RR-1030, Yale University, New Haven, Connecticut, USA, May [15] Mark P. Jones. Simplifying and improving qualified types. Research Report YALEU/DCS/RR-1040, Yale University, New Haven, Connecticut, USA, June [16] J.C. Mitchell. Coercion and type inference (summary). In Conference record of the Eleventh Annual ACM Symposium on Principles of Programming Languages, Salt Lake City, Utah, January [17] J.C. Mitchell. Type inference with simple subtypes. Journal of functional programming, 1(3): , July [18] Didier Rémy. Typechecking records and variants in a natural extension of ML. In Conference record of the Sixteenth Annual ACM Symposium on Principles of Programming Languages, Austin, TX, January [19] Geoffrey Seward Smith. Polymorphic type inference for languages with overloading and subtyping. PhD thesis, Department of Computer Science, Cornell University, Ithaca, New York, August [20] D. Volpano and G. Smith. On the complexity of ML typability with overloading. In 5th ACM conference on Functional Programming Languages and Computer Architecture, New York, Springer-Verlag. Lecture Notes in Computer Science, 523. [21] P. Wadler and S. Blott. How to make ad hoc polymorphism less ad hoc. In Proceedings of 16th ACM Symposium on Principles of Programming Languages, pages 60 76, Jan 1989.
Simplifying and Improving Qualified Types
Simplifying and Improving Qualified Types Mark P. Jones Yale University, Department of Computer Science P.O. Box 208285, New Haven, CT 06520-8285. jones-mark@cs.yale.edu Research Report YALEU/DCS/RR-1040,
A theory of qualified types
A theory of qualified types Mark P. Jones Programming Research Group Oxford University Computing Laboratory 8 11 Keble Road Oxford OX1 3QD Introduction In a language with a polymorphic type system, a term
A system of constructor classes: overloading and implicit higher-order polymorphism
A system of constructor classes: overloading and implicit higher-order polymorphism Mark P. Jones Yale University, Department of Computer Science, P.O. Box 2158 Yale Station, New Haven, CT 06520-2158.
Constrained Types and their Expressiveness
Constrained Types and their Expressiveness JENS PALSBERG Massachusetts Institute of Technology and SCOTT SMITH Johns Hopkins University A constrained type consists of both a standard type and a constraint
Where is ML type inference headed?
1 Constraint solving meets local shape inference September 2005 2 Types are good A type is a concise description of the behavior of a program fragment. Typechecking provides safety or security guarantees.
Subtyping. Lecture 13 CS 565 3/27/06
Subtyping Lecture 13 CS 565 3/27/06 Polymorphism Different varieties of polymorphism: Parametric (ML) type variables are abstract, and used to encode the fact that the same term can be used in many different
Type Classes and Instance Chains: A Relational Approach. John Garrett Morris
Type Classes and Instance Chains: A Relational Approach by John Garrett Morris A dissertation submitted in partial fulfillment of the requirements for the degree of Doctor of Philosophy in Computer Science
Extracting the Range of cps from Affine Typing
Extracting the Range of cps from Affine Typing Extended Abstract Josh Berdine, Peter W. O Hearn Queen Mary, University of London {berdine, ohearn}@dcs.qmul.ac.uk Hayo Thielecke The University of Birmingham
Advances in Programming Languages
T O Y H Advances in Programming Languages APL8: Multiparameter Type Classes, Constructor Classes Ian Stark School of Informatics The University of Edinburgh Thursday 4 February Semester 2 Week 4 E H U
Let Arguments Go First
Let Arguments Go First Ningning Xie and Bruno C. d. S. Oliveira The University of Hong Kong {nnxie,bruno}@cs.hku.hk Abstract. Bi-directional type checking has proved to be an extremely useful and versatile
Semantics via Syntax. f (4) = if define f (x) =2 x + 55.
1 Semantics via Syntax The specification of a programming language starts with its syntax. As every programmer knows, the syntax of a language comes in the shape of a variant of a BNF (Backus-Naur Form)
SORT INFERENCE \coregular" signatures, they derive an algorithm for computing a most general typing for expressions e which is only slightly more comp
Haskell Overloading is DEXPTIME{complete Helmut Seidl Fachbereich Informatik Universitat des Saarlandes Postfach 151150 D{66041 Saarbrucken Germany seidl@cs.uni-sb.de Febr., 1994 Keywords: Haskell type
From Types to Sets in Isabelle/HOL
From Types to Sets in Isabelle/HOL Extented Abstract Ondřej Kunčar 1 and Andrei Popescu 1,2 1 Fakultät für Informatik, Technische Universität München, Germany 2 Institute of Mathematics Simion Stoilow
Type Processing by Constraint Reasoning
, Martin Sulzmann, Jeremy Wazny 8th November 2006 Chameleon Chameleon is Haskell-style language treats type problems using constraints gives expressive error messages has a programmable type system Developers:
The Typed λ Calculus and Type Inferencing in ML
Notes on Types S. Arun-Kumar Department of Computer Science and Engineering Indian Institute of Technology New Delhi, 110016 email: sak@cse.iitd.ernet.in April 14, 2002 2 Chapter 1 The Typed λ Calculus
University of Utrecht. 1992; Fokker, 1995), the use of monads to structure functional programs (Wadler,
J. Functional Programming 1 (1): 1{000, January 1993 c 1993 Cambridge University Press 1 F U N C T I O N A L P E A R L S Monadic Parsing in Haskell Graham Hutton University of Nottingham Erik Meijer University
Hiding local state in direct style: a higher-order anti-frame rule
1 / 65 Hiding local state in direct style: a higher-order anti-frame rule François Pottier January 28th, 2008 2 / 65 Contents Introduction Basics of the type system A higher-order anti-frame rule Applications
the application rule M : x:a: B N : A M N : (x:a: B) N and the reduction rule (x: A: B) N! Bfx := Ng. Their algorithm is not fully satisfactory in the
The Semi-Full Closure of Pure Type Systems? Gilles Barthe Institutionen for Datavetenskap, Chalmers Tekniska Hogskola, Goteborg, Sweden Departamento de Informatica, Universidade do Minho, Braga, Portugal
Structural polymorphism in Generic Haskell
Structural polymorphism in Generic Haskell Andres Löh andres@cs.uu.nl 5 February 2005 Overview About Haskell Genericity and other types of polymorphism Examples of generic functions Generic Haskell Overview
1 Introduction. 3 Syntax
CS 6110 S18 Lecture 19 Typed λ-calculus 1 Introduction Type checking is a lightweight technique for proving simple properties of programs. Unlike theorem-proving techniques based on axiomatic semantics,
Type-directed Syntax Transformations for ATS-style Programs with Proofs
Type-directed Syntax Transformations for ATS-style Programs with Proofs Andrei Lapets August 14, 2007 1 Introduction In their work on ATS [CX05] and ATS LF [CX04], the authors present an ML-like language
Overloading, Type Classes, and Algebraic Datatypes
Overloading, Type Classes, and Algebraic Datatypes Delivered by Michael Pellauer Arvind Computer Science and Artificial Intelligence Laboratory M.I.T. September 28, 2006 September 28, 2006 http://www.csg.csail.mit.edu/6.827
Lecture Notes on Program Equivalence
Lecture Notes on Program Equivalence 15-312: Foundations of Programming Languages Frank Pfenning Lecture 24 November 30, 2004 When are two programs equal? Without much reflection one might say that two
14.1 Encoding for different models of computation
Lecture 14 Decidable languages In the previous lecture we discussed some examples of encoding schemes, through which various objects can be represented by strings over a given alphabet. We will begin this
The Design of Core C++ (Notes)
The Design of Core C++ (Notes) Uday Reddy May 13, 1994 This note is to define a small formal language called Core C++ which reflects the essential structure of C++. As the name implies, the design only
Tradeoffs. CSE 505: Programming Languages. Lecture 15 Subtyping. Where shall we add useful completeness? Where shall we add completeness?
Tradeoffs CSE 505: Programming Languages Lecture 15 Subtyping Zach Tatlock Autumn 2017 Desirable type system properties (desiderata): soundness - exclude all programs that get stuck completeness - include
The design of a programming language for provably correct programs: success and failure
The design of a programming language for provably correct programs: success and failure Don Sannella Laboratory for Foundations of Computer Science School of Informatics, University of Edinburgh http://homepages.inf.ed.ac.uk/dts
Polymorphic lambda calculus Princ. of Progr. Languages (and Extended ) The University of Birmingham. c Uday Reddy
06-02552 Princ. of Progr. Languages (and Extended ) The University of Birmingham Spring Semester 2016-17 School of Computer Science c Uday Reddy2016-17 Handout 6: Polymorphic Type Systems 1. Polymorphic
COS 320. Compiling Techniques
Topic 5: Types COS 320 Compiling Techniques Princeton University Spring 2016 Lennart Beringer 1 Types: potential benefits (I) 2 For programmers: help to eliminate common programming mistakes, particularly
Dependent Object Types - A foundation for Scala s type system
Dependent Object Types - A foundation for Scala s type system Draft of September 9, 2012 Do Not Distrubute Martin Odersky, Geoffrey Alan Washburn EPFL Abstract. 1 Introduction This paper presents a proposal
JOURNAL OF OBJECT TECHNOLOGY
JOURNAL OF OBJECT TECHNOLOGY Online at www.jot.fm. Published by ETH Zurich, Chair of Software Engineering JOT, 2002 Vol. 1, No. 2, July-August 2002 The Theory of Classification Part 2: The Scratch-Built
A Typed Lambda Calculus for Input Sanitation
A Typed Lambda Calculus for Input Sanitation Nathan Fulton Carthage College nfulton@carthage.edu April 11, 2013 Abstract Programmers often wish to validate or sanitize user input. One common approach to
CS152: Programming Languages. Lecture 11 STLC Extensions and Related Topics. Dan Grossman Spring 2011
CS152: Programming Languages Lecture 11 STLC Extensions and Related Topics Dan Grossman Spring 2011 Review e ::= λx. e x e e c v ::= λx. e c τ ::= int τ τ Γ ::= Γ, x : τ (λx. e) v e[v/x] e 1 e 1 e 1 e
Control Flow Analysis with SAT Solvers
Control Flow Analysis with SAT Solvers Steven Lyde, Matthew Might University of Utah, Salt Lake City, Utah, USA Abstract. Control flow analyses statically determine the control flow of programs. This is
Arbitrary-rank polymorphism in (GHC) Haskell
Arbitrary-rank polymorphism in (GHC) Haskell CAS 743 Stephen Forrest 20 March 2006 Damas-Milner Type System A Damas-Milner type system (also called Hindley-Milner) is a traditional type system for functional
3.7 Denotational Semantics
3.7 Denotational Semantics Denotational semantics, also known as fixed-point semantics, associates to each programming language construct a well-defined and rigorously understood mathematical object. These
To What Extend Is Type Inference for Parameteric Polymorphism Possible in the Presence of Ad-Hoc and Subtype Polymorphism
To What Extend Is Type Inference for Parameteric Polymorphism Possible in the Presence of Ad-Hoc and Subtype Polymorphism Daniel Marty University of Applied Sciences Rapperswil Supervised by Prof. Dr.
CS 6110 S11 Lecture 25 Typed λ-calculus 6 April 2011
CS 6110 S11 Lecture 25 Typed λ-calculus 6 April 2011 1 Introduction Type checking is a lightweight technique for proving simple properties of programs. Unlike theorem-proving techniques based on axiomatic
Hierarchical Pointer Analysis for Distributed Programs
Hierarchical Pointer Analysis for Distributed Programs Amir Kamil Computer Science Division, University of California, Berkeley kamil@cs.berkeley.edu April 14, 2006 1 Introduction Many distributed, parallel
Operational Semantics
15-819K: Logic Programming Lecture 4 Operational Semantics Frank Pfenning September 7, 2006 In this lecture we begin in the quest to formally capture the operational semantics in order to prove properties
CS4215 Programming Language Implementation. Martin Henz
CS4215 Programming Language Implementation Martin Henz Thursday 26 January, 2012 2 Chapter 4 The Language simpl In this chapter, we are exting the language epl in order to provide a more powerful programming
CSCI-GA Scripting Languages
CSCI-GA.3033.003 Scripting Languages 12/02/2013 OCaml 1 Acknowledgement The material on these slides is based on notes provided by Dexter Kozen. 2 About OCaml A functional programming language All computation
Once Upon a Polymorphic Type
Once Upon a Polymorphic Type Keith Wansbrough Computer Laboratory University of Cambridge kw217@cl.cam.ac.uk http://www.cl.cam.ac.uk/users/kw217/ Simon Peyton Jones Microsoft Research Cambridge 20 January,
Harvard School of Engineering and Applied Sciences CS 152: Programming Languages
Harvard School of Engineering and Applied Sciences CS 152: Programming Languages Lecture 14 Tuesday, March 24, 2015 1 Parametric polymorphism Polymorph means many forms. Polymorphism is the ability of
Chapter 2 The Language PCF
Chapter 2 The Language PCF We will illustrate the various styles of semantics of programming languages with an example: the language PCF Programming language for computable functions, also called Mini-ML.
Lists. Michael P. Fourman. February 2, 2010
Lists Michael P. Fourman February 2, 2010 1 Introduction The list is a fundamental datatype in most functional languages. ML is no exception; list is a built-in ML type constructor. However, to introduce
Let Arguments Go First
Let Arguments Go First Ningning Xie (B) and Bruno C. d. S. Oliveira The University of Hong Kong, Pokfulam, Hong Kong {nnxie,bruno}@cs.hku.hk Abstract. Bi-directional type checking has proved to be an extremely
Induction and Semantics in Dafny
15-414 Lecture 11 1 Instructor: Matt Fredrikson Induction and Semantics in Dafny TA: Ryan Wagner Encoding the syntax of Imp Recall the abstract syntax of Imp: a AExp ::= n Z x Var a 1 + a 2 b BExp ::=
Type Systems. Pierce Ch. 3, 8, 11, 15 CSE
Type Systems Pierce Ch. 3, 8, 11, 15 CSE 6341 1 A Simple Language ::= true false if then else 0 succ pred iszero Simple untyped expressions Natural numbers encoded as succ succ
Semantic Subtyping. Alain Frisch (ENS Paris) Giuseppe Castagna (ENS Paris) Véronique Benzaken (LRI U Paris Sud)
Semantic Subtyping Alain Frisch (ENS Paris) Giuseppe Castagna (ENS Paris) Véronique Benzaken (LRI U Paris Sud) http://www.cduce.org/ Semantic Subtyping - Groupe de travail BD LRI p.1/28 CDuce A functional
Introduction. chapter Functions
chapter 1 Introduction In this chapter we set the stage for the rest of the book. We start by reviewing the notion of a function, then introduce the concept of functional programming, summarise the main
Type Inference with Inequalities
Type Inference with Inequalities Michael I. Schwartzbach mis@daimi.aau.dk Computer Science Department Aarhus University Ny Munkegade DK-8000 Århus C, Denmark Abstract Type inference can be phrased as constraint-solving
Lambda Calculus and Type Inference
Lambda Calculus and Type Inference Björn Lisper Dept. of Computer Science and Engineering Mälardalen University bjorn.lisper@mdh.se http://www.idt.mdh.se/ blr/ August 17, 2007 Lambda Calculus and Type
l e t print_name r = p r i n t _ e n d l i n e ( Name : ^ r. name)
Chapter 8 Row polymorphism Consider the following code: type name_home = {name : s t r i n g ; home : s t r i n g } type name_mobile = {name : s t r i n g ; mobile : s t r i n g } l e t jane = {name =
3.4 Deduction and Evaluation: Tools Conditional-Equational Logic
3.4 Deduction and Evaluation: Tools 3.4.1 Conditional-Equational Logic The general definition of a formal specification from above was based on the existence of a precisely defined semantics for the syntax
PCP and Hardness of Approximation
PCP and Hardness of Approximation January 30, 2009 Our goal herein is to define and prove basic concepts regarding hardness of approximation. We will state but obviously not prove a PCP theorem as a starting
An LCF-Style Interface between HOL and First-Order Logic
An LCF-Style Interface between HOL and First-Order Logic Joe Hurd Computer Laboratory University of Cambridge, joe.hurd@cl.cam.ac.uk 1 Introduction Performing interactive proof in the HOL theorem prover
Part III. Chapter 15: Subtyping
Part III Chapter 15: Subtyping Subsumption Subtype relation Properties of subtyping and typing Subtyping and other features Intersection and union types Subtyping Motivation With the usual typing rule
Part III Chapter 15: Subtyping
Part III Chapter 15: Subtyping Subsumption Subtype relation Properties of subtyping and typing Subtyping and other features Intersection and union types Subtyping Motivation With the usual typing rule
Foundations of AI. 9. Predicate Logic. Syntax and Semantics, Normal Forms, Herbrand Expansion, Resolution
Foundations of AI 9. Predicate Logic Syntax and Semantics, Normal Forms, Herbrand Expansion, Resolution Wolfram Burgard, Andreas Karwath, Bernhard Nebel, and Martin Riedmiller 09/1 Contents Motivation
Thunks (continued) Olivier Danvy, John Hatcli. Department of Computing and Information Sciences. Kansas State University. Manhattan, Kansas 66506, USA
Thunks (continued) Olivier Danvy, John Hatcli Department of Computing and Information Sciences Kansas State University Manhattan, Kansas 66506, USA e-mail: (danvy, hatcli)@cis.ksu.edu Abstract: Call-by-name
Lecture Notes on Static Single Assignment Form
Lecture Notes on Static Single Assignment Form 15-411: Compiler Design Frank Pfenning Lecture 6 September 12, 2013 1 Introduction In abstract machine code of the kind we have discussed so far, a variable
CS 6110 S14 Lecture 1 Introduction 24 January 2014
CS 6110 S14 Lecture 1 Introduction 24 January 2014 1 Introduction What is a program? Is it just something that tells the computer what to do? Yes, but there is much more to it than that. The basic expressions
Lecture 5: The Halting Problem. Michael Beeson
Lecture 5: The Halting Problem Michael Beeson Historical situation in 1930 The diagonal method appears to offer a way to extend just about any definition of computable. It appeared in the 1920s that it
(Refer Slide Time: 4:00)
Principles of Programming Languages Dr. S. Arun Kumar Department of Computer Science & Engineering Indian Institute of Technology, Delhi Lecture - 38 Meanings Let us look at abstracts namely functional
STABILITY AND PARADOX IN ALGORITHMIC LOGIC
STABILITY AND PARADOX IN ALGORITHMIC LOGIC WAYNE AITKEN, JEFFREY A. BARRETT Abstract. Algorithmic logic is the logic of basic statements concerning algorithms and the algorithmic rules of deduction between
CS 6110 S11 Lecture 12 Naming and Scope 21 February 2011
CS 6110 S11 Lecture 12 Naming and Scope 21 February 2011 In this lecture we introduce the topic of scope in the context of the λ-calculus and define translations from λ-cbv to FL for the two most common
7. Introduction to Denotational Semantics. Oscar Nierstrasz
7. Introduction to Denotational Semantics Oscar Nierstrasz Roadmap > Syntax and Semantics > Semantics of Expressions > Semantics of Assignment > Other Issues References > D. A. Schmidt, Denotational Semantics,
Programming Languages Third Edition
Programming Languages Third Edition Chapter 12 Formal Semantics Objectives Become familiar with a sample small language for the purpose of semantic specification Understand operational semantics Understand
Handout 10: Imperative programs and the Lambda Calculus
06-02552 Princ of Progr Languages (and Extended ) The University of Birmingham Spring Semester 2016-17 School of Computer Science c Uday Reddy2016-17 Handout 10: Imperative programs and the Lambda Calculus
CS 242. Fundamentals. Reading: See last slide
CS 242 Fundamentals Reading: See last slide Syntax and Semantics of Programs Syntax The symbols used to write a program Semantics The actions that occur when a program is executed Programming language
CSCI B522 Lecture 11 Naming and Scope 8 Oct, 2009
CSCI B522 Lecture 11 Naming and Scope 8 Oct, 2009 Lecture notes for CS 6110 (Spring 09) taught by Andrew Myers at Cornell; edited by Amal Ahmed, Fall 09. 1 Static vs. dynamic scoping The scope of a variable
6. Relational Algebra (Part II)
6. Relational Algebra (Part II) 6.1. Introduction In the previous chapter, we introduced relational algebra as a fundamental model of relational database manipulation. In particular, we defined and discussed
Demonstrating Lambda Calculus Reduction
Electronic Notes in Theoretical Computer Science 45 (2001) URL: http://www.elsevier.nl/locate/entcs/volume45.html 9 pages Demonstrating Lambda Calculus Reduction Peter Sestoft 1 Department of Mathematics
The University of Nottingham SCHOOL OF COMPUTER SCIENCE A LEVEL 4 MODULE, SPRING SEMESTER MATHEMATICAL FOUNDATIONS OF PROGRAMMING ANSWERS
The University of Nottingham SCHOOL OF COMPUTER SCIENCE A LEVEL 4 MODULE, SPRING SEMESTER 2012 2013 MATHEMATICAL FOUNDATIONS OF PROGRAMMING ANSWERS Time allowed TWO hours Candidates may complete the front
Simple Unification-based Type Inference for GADTs
Simple Unification-based Type Inference for GADTs Stephanie Weirich University of Pennsylvania joint work with Dimitrios Vytiniotis, Simon Peyton Jones and Geoffrey Washburn Overview Goal: Add GADTs to
Verifying Program Invariants with Refinement Types
Verifying Program Invariants with Refinement Types Rowan Davies and Frank Pfenning Carnegie Mellon University Princeton and Yale Colloquium Talks February, 2001 Acknowledgments: Robert Harper 1 Overview
Second-Order Type Systems
#1 Second-Order Type Systems Homework 5 Summary Student : 37.9704 Student : 44.4466 ORIGINAL : 50.2442 Student : 50.8275 Student : 50.8633 Student : 50.9181 Student : 52.1347 Student : 52.1633 Student
Formally-Proven Kosaraju s algorithm
Formally-Proven Kosaraju s algorithm Laurent Théry Laurent.Thery@sophia.inria.fr Abstract This notes explains how the Kosaraju s algorithm that computes the strong-connected components of a directed graph
A Simplified Abstract Syntax for the Dataflow Algebra. A. J. Cowling
Verification and Testing Research Group, Department of Computer Science, University of Sheffield, Regent Court, 211, Portobello Street, Sheffield, S1 4DP, United Kingdom Email: A.Cowling @ dcs.shef.ac.uk
Tracing Ambiguity in GADT Type Inference
Tracing Ambiguity in GADT Type Inference ML Workshop 2012, Copenhagen Jacques Garrigue & Didier Rémy Nagoya University / INRIA Garrigue & Rémy Tracing ambiguity 1 Generalized Algebraic Datatypes Algebraic
INCREMENTAL SOFTWARE CONSTRUCTION WITH REFINEMENT DIAGRAMS
INCREMENTAL SOFTWARE CONSTRUCTION WITH REFINEMENT DIAGRAMS Ralph-Johan Back Abo Akademi University July 6, 2006 Home page: www.abo.fi/~backrj Research / Current research / Incremental Software Construction
Meta-programming with Names and Necessity p.1
Meta-programming with Names and Necessity Aleksandar Nanevski Carnegie Mellon University ICFP, Pittsburgh, 05 October 2002 Meta-programming with Names and Necessity p.1 Meta-programming Manipulation of
This is already grossly inconvenient in present formalisms. Why do we want to make this convenient? GENERAL GOALS
1 THE FORMALIZATION OF MATHEMATICS by Harvey M. Friedman Ohio State University Department of Mathematics friedman@math.ohio-state.edu www.math.ohio-state.edu/~friedman/ May 21, 1997 Can mathematics be
axiomatic semantics involving logical rules for deriving relations between preconditions and postconditions.
CS 6110 S18 Lecture 18 Denotational Semantics 1 What is Denotational Semantics? So far we have looked at operational semantics involving rules for state transitions, definitional semantics involving translations
Lecture 9: Typed Lambda Calculus
Advanced Topics in Programming Languages Spring Semester, 2012 Lecture 9: Typed Lambda Calculus May 8, 2012 Lecturer: Mooly Sagiv Scribe: Guy Golan Gueta and Shachar Itzhaky 1 Defining a Type System for
Inheritance and Overloading in Agda
Inheritance and Overloading in Agda Paolo Capriotti 3 June 2013 Abstract One of the challenges of the formalization of mathematics in a proof assistant is defining things in such a way that the syntax
Overview. Elements of Programming Languages. Another example. Consider the humble identity function
Overview Elements of Programming Languages Lecture 8: Polymorphism and type inference James Cheney University of Edinburgh October 21, 2016 This week and next week, we will cover di erent forms of abstraction
Type Systems, Type Inference, and Polymorphism
6 Type Systems, Type Inference, and Polymorphism Programming involves a wide range of computational constructs, such as data structures, functions, objects, communication channels, and threads of control.
Introduction to lambda calculus Part 3
Introduction to lambda calculus Part 3 Antti-Juhani Kaijanaho 2017-01-27... 1 Untyped lambda calculus... 2 Typed lambda calculi In an untyped lambda calculus extended with integers, it is required that
One of a number of approaches to a mathematical challenge at the time (1930): Constructibility
λ Calculus Church s λ Calculus: Brief History One of a number of approaches to a mathematical challenge at the time (1930): Constructibility (What does it mean for an object, e.g. a natural number, to
Recursively Enumerable Languages, Turing Machines, and Decidability
Recursively Enumerable Languages, Turing Machines, and Decidability 1 Problem Reduction: Basic Concepts and Analogies The concept of problem reduction is simple at a high level. You simply take an algorithm
Lecture Notes on Real-world SMT
15-414: Bug Catching: Automated Program Verification Lecture Notes on Real-world SMT Matt Fredrikson Ruben Martins Carnegie Mellon University Lecture 15 1 Introduction In the previous lecture we studied
6.001 Notes: Section 8.1
6.001 Notes: Section 8.1 Slide 8.1.1 In this lecture we are going to introduce a new data type, specifically to deal with symbols. This may sound a bit odd, but if you step back, you may realize that everything
CONVENTIONAL EXECUTABLE SEMANTICS. Grigore Rosu CS522 Programming Language Semantics
CONVENTIONAL EXECUTABLE SEMANTICS Grigore Rosu CS522 Programming Language Semantics Conventional Semantic Approaches A language designer should understand the existing design approaches, techniques and
Introduction to Homotopy Type Theory
Introduction to Homotopy Type Theory Lecture notes for a course at EWSCS 2017 Thorsten Altenkirch March 5, 2017 1 What is this course about? To explain what Homotopy Type Theory is, I will first talk about
Beluga: A Framework for Programming and Reasoning with Deductive Systems (System Description)
Beluga: A Framework for Programming and Reasoning with Deductive Systems (System Description) Brigitte Pientka and Joshua Dunfield McGill University, Montréal, Canada {bpientka,joshua}@cs.mcgill.ca Abstract.
Coq with Classes. Matthieu Sozeau. Journées PPS 2011 September 5th 2011 Trouville, France. Project Team πr 2 INRIA Paris
Coq with Classes Matthieu Sozeau Project Team πr 2 INRIA Paris Journées PPS 2011 September 5th 2011 Trouville, France This talk A quick overview of Coq Elaboration Type Classes Matthieu Sozeau - Coq with
Introduction to Programming, Aug-Dec 2006
Introduction to Programming, Aug-Dec 2006 Lecture 3, Friday 11 Aug 2006 Lists... We can implicitly decompose a list into its head and tail by providing a pattern with two variables to denote the two components
1. true / false By a compiler we mean a program that translates to code that will run natively on some machine.
1. true / false By a compiler we mean a program that translates to code that will run natively on some machine. 2. true / false ML can be compiled. 3. true / false FORTRAN can reasonably be considered