CS 565 October 6, 1997 Jens Palsberg Readings: Efficient Recursive Subtyping

Lecture Note 8:

Structural Subtyping and Recursive Types

Contents

1 Recursive Types 2 2 Subtyping 5 3 Efficient Recursive Subtyping 8 4 Amadio and Cardelli’s Original Algorithm 9 5 The Fast Algorithm 10 6 Example 11 7 Terms 12 8 The Type Ordering 14 9 Basic Result 15 10 Algorithm 16 11 Tree Truncations 17 12 Equivalence Result 18

1 Recursive Types

Simple types are finite. When we draw a simple type as a tree, it is finite. One of the consequences is that we cannot type all λ-terms with simple types. For example, consider the λ-term λx.xx. Like in Lecture Note 7, let us think of it as λx.x_{1}x_{2}. The constraints are:

⟨x⟩ → [[x_{1}x_{2}]] = [[λx.x_{1}x_{2}]]
[[x_{1}]] = [[x_{2}]] → [[x_{1}x_{2}]]
⟨x⟩ = [[x_{1}]]
⟨x⟩ = [[x_{2}]]

Some unification gives:

[[x_{1}]] = [[x_{2}]] → [[x_{1}x_{2}]]
= ⟨x⟩ → [[x_{1}x_{2}]]
= [[x_{1}]] → [[x_{1}x_{2}]]

In other words, the type for x_{1} must be a function type which has itself as the domain type! This is not possible with a finite type, so from Theorem 1 of Lecture Note 7 we get that λ-term λx.xx is not typable. Suppose now that we allow types to be infinite. We change the grammar of types to:

t ::= t_{1} → t_{2} | Int | α | μα.t

where α is a variable that ranges over types, and μα.t is a recursive type which allow the unfolding:

μα.t = t[(μα.t)/α]

The notation t[s/α] is the notation for substitution that we studied in Lecture Note 3. For example, let u be the type μα.(α → Int). By unfolding once, we get that u = u → Int. By unfolding twice, we get that u = (u → Int) → Int. If we unfold infinitely, we get an infinite tree. That tree is the meaning of u. Draw it!

There is just one thing to be careful about: if a type contains a pattern of the form

μα_{1}.μα_{2}…. μα_{n}.α_{1}

then we cannot unfold it into something other than itself! Such a pattern is called a Black Hole and we will not consider it to be a type. In summary, if we generate something from the grammar above, and it does not contain a Black Hole, then we can unfold into an infinite tree where all the μs have disappeared. That infinite tree is the type. Such a type will always have only finitely many distinct subtrees. Trees of that kind are called regular trees. Conversely, any regular tree can be written as a finite expression with μs. (We are not going to study the proofs of these claims here.) Let consider again the λ-term λx.xx. With the type u = μα.(α → Int) it is easy to solve the system of constraints and to build a type derivation. Here is the type derivation:

\frac{\{x : u\} ⊢ u → Int \{x : u\} ⊢ u}{\{x : u\} ⊢ xx : Int}

∅ ⊢ λx.xx : u → Int

In the left part of the tree we have {x : u} ⊢ u → Int and this is okay because u = u → Int. Let us consider another application of the type u = μα.(α → Int). There is a famous λ-term which is known as the “paradoxical combinator.” This λ-term has the property that when applied to a function g, then it produces a fixed point of g. The λ-term is:

Y = λf.(λx.f(xx))(λx.f(xx))

Notice that for any λ-term E we have

Y (E) ⇝_{β} (λx.E(xx))(λx.E(xx))
⇝_{β} E((λx.E(xx))(λx.E(xx)))
=_{β} E(Y (E))

So, Y (E) is a fixed point of E!

Can we type Y? Not with simple types. But it is easy with recursive types. Let us again use the type u = μα.(α → Int). Here is part of the type derivation:

\frac{\{f : Int → Int\} ⊢ (λx.f(xx))(λx.f(xx)) : Int}{∅ ⊢ λf.(λx.f(xx))(λx.f(xx)) : (Int → Int) → Int}

It is easy to see that if λx.f(xx) has type u, then we can use u = u → Int to get the hypothesis of the above derivation. So we must derive

{f : Int → Int} ⊢ λx.f(xx) : u

We will give x the type u → Int, which is actually u, and we must then show that f(xx) has type Int. This in turn mean that xx must have type Int. This is easy to achieve because u = u → Int. Here is most of the type derivation:

\frac{\{f : Int → Int, x : u\} ⊢ f : Int → Int \{f : Int → Int, x : u\} ⊢ xx : Int}{\{f : Int → Int, x : u\} ⊢ f(xx) : Int}

{f : Int → Int} ⊢ λx.f(xx) : u

It is easy to see that we can replace Int with any other type and still have a valid type derivation. Let us say that a λ-term with only abstractions, applications, and variables is a pure λ-term. Thus, a pure λ-term does not contain 0 or succ. Recursive types are sufficient to type all pure λ-terms. There is even a type which types all pure λ-terms! Consider the type B = μα.(α → α). The tree for this type expression is a full, binary, infinite tree with → as the label in all the nodes. Draw it! By unfolding once we see that B = B → B. Let us say that a type environment is a t-environment if all the type variables in its domain are mapped to t. Theorem 2 If A is a B-environment which is defined (at least) for all free variables in the λ-term E, then A ⊢ E : B. It is easy to prove this by induction on the structure of E. Not all λ-terms can be typed with recursive types. For example,

λx.x(succ x)

is a quite weird λ-term that we cannot type even with recursive types. The good news is that Theorem 1 also holds for recursive types: same type rules, same constraints, but recursive types instead of simple types.

2 Subtyping Motivation: typing functions in object-oriented languages.

t ::= ⊤ | t → t (types)

Type ordering: t ≤ ⊤ for any type t. One extra typing rule: subsumption.

\frac{A ⊢ E : t t ≤ t′}{A ⊢ E : t′}

Partial Types

t ::= ⊤ | t → t (types)

t ≤ ⊤ for any type t. Add the usual rule for ordering function spaces: s → t ≤ s′ → t′ if and only if s′ ≤ s and t ≤ t′. Typed terms are strongly normalizing [Wand 92]. Every normal form is typable [Palsberg, Inf. Proc. Letters]. Type inference:

• [Thatte ICALP’88]:

Semi-decidable

• [O’Keefe, Wand ESOP’92]:

Exponential time

• [Kozen, Palsberg, Schwartzbach FOCS’92]: Cubic time Subtyping and Recursive Types Found in Amber and Quest.

t ::= v | ⊥ | ⊤ | t → t | μv.t (types) Studied by Amadio and Cardelli [POPL’91]. ⊥ ≤ t for any type t

(v ≤ v′ ⇒ t ≤ t′) ⇒ (μv.t ≤ μv′.t′) Representing types as labeled trees:

μu.((u → u) → ⊥) ≤ μv.((v → ⊥) → ⊤)

[figure: →; →; →; →; ⊥; ⊥; ⋮; ⋮; ⋮; →; →; →; →; ⊤; ⊤; ⊥; ⊥; ⋮]

3 Efficient Recursive Subtyping

The Result

An efficient algorithm that decides if one recursive type is a subtype of another.

t ::= v | ⊥ | ⊤ | t → t | μv.t (types)

Amadio and Cardelli (POPL’91): Exponential time. Kozen, Palsberg, and Schwartzbach (POPL’93): O(n^{2}) time.

4 Amadio and Cardelli’s Original Algorithm Problem: Given two types s and t, is s ≤ t? Definition Two trees are ordered if all their finite truncations are ordered. Concrete representation of trees involving back-pointers. Explicit construction of a binary proof tree of polynomial depth. Time complexity: exponential.

5 The Fast Algorithm

Definition Two trees are ordered if no common path detects a counterexample.

Theorem The new definition is equivalent to Amadio and Cardelli’s.

Representation of trees as term automata.

A certain product automaton accepts all counterexamples.

Time complexity: O(n^{2}) time.

6 Example

μv.(v → ⊥) ≰ μu.(u → ⊤)

[figure: →; →; ⊥; ⊥; ⋮; →; →; ⊤; ⊤; ⋮]

[figure: 0; 1; →_{v}; ⊥] [figure: 0; 1; →_{u}; ⊤] Product automaton:

[figure: 1; 1; 0; 0; ((⊥, ⊤, 1)); (⊥, ⊤, 0); (→_{v}, →_{u}, 1); (→_{v}, →_{u}, 0)]

Ordering: ⊥ ≤ → ≤ ⊤. Perhaps reverse? 0 means “no”, 1 means “yes”.

7 Terms Intuition: a term is a labeled tree. Σ, a finite ranked alphabet. In our application: Σ = {⊥, →, ⊤}. A term over Σ is a partial function

t : ω∗ → Σ

with domain D(t) satisfying • D(t) is nonempty and prefix-closed;

• if t(α) ∈ Σ_{n},

then {i | αi ∈ D(t)} = {0, 1, …, n − 1}. The set of all terms over Σ is denoted T_{Σ}. A term t is finite if its domain D(t) is a finite set. We denote the set of finite terms over Σ by F_{Σ}.

Subterms

Subterms: t↓α(β) = t(αβ) A term t is regular if it has only finitely many distinct subterms; i.e., if {t↓α | α ∈ ω∗} is a finite set.

Example terms:

[figure: f; g; g; a; f; a; b; f; f; f; f; a; a; a; a; ⋮]

If t is a term, then the following are equivalent:

(i) t is regular; (ii) t is representable by a term automaton; (iii) t is described by a finite set of equations

involving the μ operator.

8 The Type Ordering

Types are terms over Σ = {⊥, →, ⊤}. Over this signature, every D(t) ⊆ {0, 1}∗. The order ≤_{FIN} is the smallest binary relation on F_{Σ} such that

(i) ⊥ ≤_{FIN} t ≤_{FIN} ⊤ for all finite t;

(ii) if s′ ≤_{FIN} s and t ≤_{FIN} t′ then s → t ≤_{FIN} s′ → t′.

The parity of α ∈ {0, 1}∗ is the number mod 2 of 0’s in α. The parity of α is denoted πα. A string α is said to be even if πα = 0 and odd if πα = 1. Let ≤_{0} be the linear order

⊥ ≤_{0} → ≤_{0} ⊤

on Σ, and let ≤_{1} be its reverse

⊤ ≤_{1} → ≤_{1} ⊥ .

For s, t ∈ T_{Σ}, define s ≤ t if s(α) ≤_{πα} t(α) for all α ∈ D(s) ∩ D(t).

9 Basic Result

The relation ≤ is a partial order on T_{Σ}, and agrees with ≤_{FIN} on F_{Σ}. In particular, for any s, t, s′, t′,

(i) ⊥ ≤ t ≤ ⊤

(ii) t ≤ ⊥ if and only if t = ⊥

(iii) ⊤ ≤ t if and only if t = ⊤

(iv) s → t ≤ s′ → t′ if and only if s′ ≤ s and t ≤ t′.

Recall that s ≰ t iff {α ∈ D(s) ∩ D(t) | s(α) ≰_{πα} t(α)} is nonempty.

Theorem A certain product automaton accepts

{α ∈ D(s) ∩ D(t) | s(α) ≰_{πα} t(α)}

10 Algorithm

Input: Two types s and t Output: Is s ≤ t?

1. Construct the term automata for s and t (linear time).

2. Construct the product automaton as sketched before (size O(n^{2})).

3. Decide, using depth first search, if the product automaton accepts the empty set (linear time).

4. If so then s ≤ t else s ≰ t.

Time complexity: O(n^{2}).

11 Tree Truncations The level-k truncations t|_{k}, t⌈_{k}, and t⌊_{k} of the term t are defined by D(t|_{k}) = D(t⌈_{k}) = D(t⌊_{k}) = {α ∈ D(t) | |α| ≤ k} and

t|_{k}(α) = \{ \begin{matrix}t(α), & |α| < k \\ ⊤, & |α| = k \end{matrix}
t⌈_{k}(α) = \{ \begin{matrix}t(α), & |α| < k \\ ⌈α⌉, & |α| = k \end{matrix}
t⌊_{k}(α) = \{ \begin{matrix}t(α), & |α| < k \\ ⌊α⌋, & |α| = k \end{matrix}

where

⌈α⌉ = \{ \begin{matrix}⊥, & α even \\ ⊤, & α odd, \end{matrix} ⌊α⌋ = \{ \begin{matrix}⊤, & α even \\ ⊥, & α odd. \end{matrix}

Notice that t⌈_{k} ≤_{FIN} t⌈_{k+1} 12 Equivalence Result

Lemma: For any k ≥ 0 and terms s and t, the following are equivalent:

• s|_{k} ≤_{FIN} t|_{k}

• s⌈_{k} ≤_{FIN} t⌈_{k}

• s⌊_{k} ≤_{FIN} t⌊_{k}.

Definition: Amadio-Cardelli’s order ≤_{AC} is defined as

s ≤_{AC} t ⟺ s|_{k} ≤_{FIN} t|_{k} for all k ≥ 0 .

Theorem: The relation ≤ agrees with ≤_{AC}.