Google May 29th, 2012
What is Symmetry? Definition Symmetry: Two or more things that initially look distinct, may actually be instances of a more general underlying principle. Why do we care? Simplicity. Simpler syntax. Fewer inference rules. Power. Can express some programs more directly. More programs are typeable.
Outline Pure Type Systems Symmetry between objects, types, and kinds. Symmetry between typing and kinding. Higher-order subtyping Generalize subtyping. Personal research: Pure Subtype Systems Symmetry between values and proper types. Symmetry between typing and subtyping. Subtyping: metatheory and proof techniques Symmetry between preservation and transitivity elimination.
Part I Pure Type Systems
The story so far: λ System λ (a.k.a. simply-typed λ-calculus) TAPS, Chapter 9. Provides ordinary functions, from object to object. Objects have types. description maps syntax proper type ordinary functions object object λx : T. u T U (Note: Pierce distinguishes between terms and types. I use the word object instead of term; this will be important later on.)
The story so far: System F System F (a.k.a. polymorphic λ-calculus) TAPS, Chapter 23. Adds type variables X. Adds functions from types to objects. E.g. map : A. B. (A B) [A] [B] description maps syntax proper type ordinary functions: object object λx : T. u T U polymorphism: type object λx. t X. T
The story so far: System F ω System F ω (a.k.a. type operators or higher-order types) TAPS, Chapter 30. Adds functions from types to types. E.g. List is a function; List<Int>, List<String>, are types. Types have kinds. Kinding is a copy of typing, one level up. description maps syntax type/kind ordinary functions: object object λx : T. u T U polymorphism: type object λx :: K. t X :: K. T type operators: type type λx :: K 1. T K 1 K 2
Looking ahead: the Calculus of Constructions The Calculus of Constructions (a.k.a. dependent types) Coquand and Huet, 1986 Adds functions from objects to types. E.g. Array<int, 128> The array type is parameterized by its size, which is an integer. X. T syntax extended to ordinary function types; function return type may depend on arguments. description maps syntax type/kind ordinary functions: object object λx : T. u x : T. U polymorphism: type object λx :: K. t X :: K. T type operators: type type λx :: K 1. T X :: K 1. K 2 dependent types: object type λx : T. U x : T. K
Getting ugly What a mess! Three sorts of term, which are syntactically distinct. objects, types, and kinds. E.g. x for object variables, X for type variables. Two relations: typing (:) and kinding (::). Four sorts of functions: object object, type object, type type, object type
Some obvious symmetries Typing and kinding rules are exactly the same. Γ, x : T u : U Γ λx : T. u : T U Γ, X :: K 1 T :: K 2 Γ λx :: K 1. T :: K 1 K 2 No need to distinguish between typing and kinding. No need to distinguish syntactically between objects, types, and kinds
Pure Type Systems Pure Type Systems (Barendregt, 1992) Terms t, u range over objects, types, and kinds. Typing (t : T ) and kinding (T :: K) are unified. Only one relation: typing. The typing relation is defined over all terms. description maps syntax type/kind functions: any any λx : t. u Πx : t. s The Πx : t. s syntax unifies the different function types: and Π are the same thing. T U is sugar for Πx : T. U, where x U. K 1 K 2 is sugar for ΠX : K 1. K 2, where X K 2.
Core PTS definitions S ::= sorts s, t, u ::= terms S sort x variable λx : t. u function Πx : t. u function type t(u) function application Γ : x : t Γ Γ x : t Γ t : Πx : u. s, u : u Γ t(u) : [x u]s Γ Πx : t. s : S Γ, x : t u : s Γ λx : t. u : Πx : t. s Γ t : S Γ, x : t u : S Γ Πx : t. u : S (S, S) R
Some Subtleties It is still possible to distinguish between objects, types, and kinds. The syntax has been unified......but the typing judgement tells you which is which. t : u : means that t is an object, u is a type t : u : means that t is a type, u is a kind
The λ-cube Relation R controls which dependencies are allowed. Eight λ-calculi in one! x axis: dependent types y axis: polymorphism z axis: type operators F ω CC F λ λp
Part II Higher Order Subtyping
What is subtyping? A proper type denotes a set of objects. Typing denotes the is a member of relation. (e.g. 3 : Nat) Subtyping denotes the subset relation. (e.g. Nat <: Top) Object Plant Animal Cat Dog Rock Top Nat 3 5 List(Nat) [2,3] [] Fluffy
Two uses of subtyping Subtype polymorphism (loosen constraint on objects) A function can accept arguments of many different types. Alternative to parametric polymorphism (i.e. System F) Widely used in object-oriented languages. void writetofile(serializable obj); Bounded quantification (tighten constraint on types) Used to constrain type arguments. Alternative to kinding (X <: T vs. X :: K) class SerializableArray<T extends Serializable> Γ t : U, U <: T Γ t : T Γ, X <:T u : U Γ λx <: T. u : X <: T. U
Higher-order subtyping Subtyping is lifted pointwise to type operators. F <: G if and only if F (X) <: G(X) for any X. Example: a List is a Container. List<T > <: Container<T > for any type T. List<Integer> <: Container<Integer> List<String> <: Container<String> Subtyping means more than just subset! // Java example : c l a s s Container <X> {... } c l a s s L i s t <X> e x t e n d s Container <X> {... }
Higher order subtyping: key rules Subtyping over functions: Γ, X <: T U <: S Γ λx <: T. U <: λx <: T. S Subtyping over function application: Γ T <: U Γ T (S) <: U(S)
System F ω <: TAPS, Chapter 31. Adds subtyping and bounded quantification to System F ω. Two versions: type operators with kinding (TAPS Chapter 31) type operators with bounded quantification description maps syntax type/kind ordinary functions: object object λx : T. u T U polymorphism: type object λx <: T. u X <: T. U type operators: type type λx :: K 1. U K 1 K 2
Getting even more ugly An even bigger mess! Three sorts of term: objects, types, and kinds. Three relations: typing (:), subtyping (<:), and kinding (::) Three sorts of functions: object object, type object, type type,
Part III Pure Subtype Systems
Typing, subtyping, and kinding description maps syntax type/kind ordinary functions: object object λx : T. u T U polymorphism: type object λx <: T. u X <: T. U type operators: type type λx :: K 1. U K 1 K 2
Pure Subtype Systems PSS simplify System F ω <:, much like PTS simplify System F ω. Terms s, t, u range over both objects and types (like PTS). Only one syntax for functions (like PTS). Key idea: unify typing, subtyping, and kinding. One relation: subtyping. Subtyping is defined over all terms. Objects are subtypes of types. e.g. 3 <: Nat <: Top (instead of 3 : Nat <: Top) Subtyping a substitute for typing. No distinction between values and proper types. Exploit a new symmetry not part of PTS.
Typing, subtyping, and kinding We already know that typing and kinding can be unified. Same as in PTS. Subtyping is strictly stronger than kinding. (Pierce) Introduce a universal supertype Top. Every kind K is associated with a bounding type T. X :: becomes X <: Top X :: becomes X <: (λy <: Top.Top) etc. Still need to unify subtyping and typing...
Typing vs. subtyping Γ, x <: t u : s Γ λx <: t. u : Πx <: t. s Γ, x <: t u <: s Γ λx <: t. u <: λx <: t. s Γ, x <: t u <: s Γ Πx <: t. u <: Πx <: t. s Typing Subtyping Typing compares λ and Π. Subtyping compares λ and λ, or Π and Π. λ is a value, whereas Π is a proper type. Can we unify λ and Π?
The symmetry of values Proper types describe the shape of values. Every distinct kind of value has a corresponding type. description value type unit unit Unit functions λx : T. u Πx : T.U records {l i = t i 1..n i } {l i : T i 1..n pairs (t, u) (T, U) i }
The symmetry of values, ctd. Traditional type theory: Values can be eliminated by reduction. E.g. {l i = ti i 1..n }.l i t i Proper types cannot be eliminated. E.g. {l i : Ti i 1..n }.l i is not a valid type. Pure Subtype Systems: Use a single syntax for values and proper types. Elimination rules apply to both values and proper types. e.g. {foo : 3, bar : 5}.foo 3 e.g. {foo : Int, bar : Int}.foo Int
Example: natural numbers Review: Church encodings of natural numbers in System F: 3 = λx. λf : X X. λa : X. f(f(f(a))) Nat = X. (X X) X X Church encodings using subtyping, in System F ω <:: 3 = λx <: Top. λf <: X X. λa <: X. F (F (F (A))) Nat = λx <: Top. λf <: X X. λa <: X. X We don t really need a new theory; we re just exploiting symmetry in an existing theory.
Double Vision 3 = λx <: Top. λf <: x x. λa <: x. f(f(f(a))) Nat = λx <: Top. λf <: x x. λa <: x. x 3 <: Nat The number 3 can be used as a type or an object. As an object, it can be used in addition, etc. It is also a singleton type: the type of all numbers equal to 3. Set theory: 3 N versus {3} N The type Nat can be used as a type or an object. As a type, it is the type of natural numbers. It can also be used in addition, etc. Nat + 3 = Nat. Operations on types are a bit like abstract interpretation. A type represents a set of possible values. Operations on types produce a set of possible results.
Desconstructing Typing The typing judgement provides three pieces of information: 1 Types describe the shape of value that will be produced when a term is evaluated; e.g. t : (Πx : U. S) means t will evaluate to a function. 2 A term which has a type is well-typed. Well-typed terms can t go wrong i.e. certain errors cannot occur during the evaluation of a well-typed term. 3 Typing determines the level (object, type, or kind) of a term.
Reconstructing Typing Pure Subtype Systems use three separate judgements: 1 Subtyping (t <: u) compares the shape of terms. e.g. t <: (λx <: u. s) means that t will evaluate to a function. 2 Well-formedness (t wf) identifies the well-typed terms. Well-formed terms can t go wrong. 3 A universe judgement (t U(K)) distinguishes between types and objects. (For simplicity, we use only a single universe.)
System λ : Syntax and well-formed terms s, t, u ::= Terms x variable Top universal supertype λx <: t. u function t(u) application Top wf x <: t Γ Γ x wf Γ t wf Γ, x <: t u wf Γ λx <: t. u wf Γ t wf, u wf Γ t <: (λx <: s. s ), Γ t(u) wf u <: s
Subtyping and equivalence: Core Rules Γ s <: t, t <: u, t wf Γ s <: u Γ x <: t Γ Γ x <: t Γ t <: Top Γ, x <: t u <: s Γ λx <: t. u <: λx <: t. s Γ t <: u Γ t(s) <: u(s) Γ (λx <: t. u)(s) [x s]u
Part IV Metatheory of Subtyping
Review: Type Soundness Standard proof technique is by progress and preservation. Progress: if t : T, then either t is a value, or t t. Preservation: if t : T and t t, then t : T. Preservation: Example: T T Int Int : : : : t t (λx : Int. x)(3) 3
Review: Inversion of typing Consider the following reduction: (λx : T.u)(s) [x s]u Typing derivations are unique. Thus, we can invert the typing relation. (λx : T.u)(s) : U only if x : T u : U, and s : T. Preservation follows by the substitution lemma.
The problem with transitivity Subtyping has no inversion lemma, because of transitivity: s <: t t <: u s <: u The term t is present in the premise, but not the conclusion. Transitivity is not algorithmic. An algorithm trying to prove s <: u, would need to guess t. The term t could be anything. Any subtyping derivation can end in transitivity. Subtyping derivations are not unique. Cannot invert the subtype relation. With no inversion lemma, cannot prove type soundness. We need to show that: (λx <: t. u) <: (λx <: t. u ) only if t t.
Metatheory: transitivity elimination Standard approach: transitivity elimination. Formulate algorithmic subtyping without a transitivity rule. Show that transitivity is admissible in the algorithmic system. i.e. transitivity can be derived from other rules. If s <: t and t <: u are transitivity-free derivations, then there exists a transitivity-free derivation of s <: u. Standard formulation: (Pierce & Steffen, Compagnoni & Goguen) Reduce all expressions to normal form. Subtyping between normal forms are transitive. Only works for strongly-normalizing theories!
Strong normalization Strongly normalizing Not strongly normalizing
Strong normalization, the real definition A normal form is a term that cannot be further reduced. The number 3 is a normal form; 1 + 2 is not. λx : T. x(x) is a normal form; (λx : T. x)(y) is not. A type theory is strongly normalizing if all terms can be reduced to normal form. i.e. the evaluation of all terms must terminate. no loops or general recursion. Example: the simply-typed λ-calculus. In most real-world languages: Type expressions are strongly normalizing. Object expressions are not strongly normalizing. Pure Subtype Systems eliminate the distinction between types and objects. Oops.
An alternative approach to transitivity elimination Type equivalence is also transitive: s t t u s u How do we handle equivalence? Standard approach: Formulate equivalence as a reduction system. Two types are equivalent if they have a common reduct: t u iff t u Transitivity follows from confluence of reduction. No need for strong normalization!
Confluence Confluence states that the order in which expressions are evaluated does not matter. It is a fundamental property of the λ-calculus. More formally: t 0 t 1 Example: t 2 t 3 (1 2) + (3 4) 2 + (3 4) (1 2) + 12 2 + 12
Subtype reduction Formulate algorithmic subtyping as a reduction system. t u reduces t to an equivalent term u. u simplifies t to a supertype u. t <: u iff t <: u. t <: Γ s <: t Γ (λx <: t. u)(s) [x s]u x <: t Γ Γ x <: t Γ t <: Top
Preservation of subtyping. <: Subtyping is sound if and commute. Commutativity is confluence with two kinds of reduction. This property looks a lot like preservation. Except that we allow reductions on the top edge. Commutativity: Example: u u (λx <: Int. Int)(3) Int <: <: <: <: t t (λx <: Int. x)(3) 3
Proof: transitivity elimination If s <: t <: u then s <: u. u <: <: t <: s
Confluence: proofs and related properties There are 3 properties related to confluence. It is almost impossible to prove confluence directly. The diamond property is strictly stronger than confluence. Local confluence is strictly weaker. (Need an additional induction principle to get confluence.) Confluence t 0 t 1 t 2 t 3 Diamond Property t 0 t 1 t 2 t 3 Local Confluence t 0 t 1 t 2 t 3
The bad news Subtype reduction commutes locally. It is very hard to prove that it commutes globally. (λx <: a. a)(c) a <: <: (λx <: a. x)(c) c
Bring back the types! Problem: too much symmetry. Solution: restore distinction between types and objects. Define a subset of terms that are strongly normalizing. Call them types. Functions must be written λx <: T. u, where T is a type. Can now prove that <: and commute. But... weren t we trying to avoid strong normalization? We don t need normalization for all terms. We only need normalization for terms that are used as types. Makes sense: what would inhabit a non-terminating type? (Translation: what objects have such a type?)
Cheap tricks How to define the strongly normalizing subset? Option 1: Use more than one universe. Beautiful. Elegant. Can you tell me how? Strong normalization proofs are really, really hard. Option 2: Require that types be well-kinded. Sad that we can t eliminate kinding altogether, though... Option 3: Require that types be in normal form to start with. Normal forms are not stable under substitution. e.g. x(y) is a normal form......but substituting a function for x yields a redex. Cheap trick: change the way that substitution is done. Use administrative normal form. (Cormac et. al., 1993) Substitution only replaces variables with variables. Hoorah! Closely resembles the nominal subtyping found in Java.
Metatheory of subtyping: summary Transitivity is evil. Must prove transitivity elimination for any theory of subtyping. Transitivity elimination is essentially a preservation theorem; it shows that subtyping is sound. Also: the more symmetric and powerful your theory, the harder the meta-theory becomes.
Part V Applications
Modules module A { type Expr <: Object ; e v a l ( e : Expr ) : I n t ; } ; module B e x t e n d s A { type Expr =... ; e v a l ( e : Expr ) : I n t =... ; } ; Is module A an object, or a type? Hard to say... A.eval is an object. A.expr is a type. Need subtyping to handle inheritance. Need dependent types for type members. Pure subtype sytems make this much simpler.
Questions?