Polymorphism, subtyping and type inference in MLsub - ML Family ...

0 downloads 188 Views 114KB Size Report
Sep 3, 2015 - Polymorphism, subtyping and type inference in. MLsub. Stephen Dolan and Alan Mycroft ... We have two trick
Polymorphism, subtyping and type inference in MLsub

Stephen Dolan and Alan Mycroft September 3, 2015 Computer Laboratory University of Cambridge

Avoiding the hard problems

Type inference with subtyping is traditionally considered difficult.

We have two tricks for getting around the difficulties: • Define types properly • Only use half of them

2

Avoiding the hard problems

Type inference with subtyping is traditionally considered difficult.

We have two tricks for getting around the difficulties: • Define types properly • Only use half of them

2

Standard definition of types and subtyping Types are either ⊥, > or functions: τ = ⊥|>|τ →τ

3

Standard definition of types and subtyping Types are either ⊥, > or functions: τ = ⊥|>|τ →τ ⊥ is the least, > is the greatest, and functions have contravariant arguments and covariant results: ⊥≤τ

τ ≤>

τ10 ≤ τ1 τ2 ≤ τ20 τ1 → τ2 ≤ τ10 → τ20

3

Lattice structure

Any two types have a greatest common subtype (u) and a least common supertype (t).

For instance: (τ1 → τ2 ) t (τ3 → τ4 ) = (τ1 u τ3 ) → (τ2 t τ4 ) Quite a well-behaved structure!

4

Bizzarely difficult questions Is this true, for all α? α→α≤⊥→>

5

Bizzarely difficult questions Is this true, for all α? α→α≤⊥→> How about this? (⊥ → >) → ⊥ ≤ (α → ⊥) t α

5

Bizzarely difficult questions Is this true, for all α? α→α≤⊥→> How about this? (⊥ → >) → ⊥ ≤ (α → ⊥) t α

Yes, it turns out, by case analysis on α.

5

Bizzarely difficult questions Is this true, for all α? α→α≤⊥→> How about this? (⊥ → >) → ⊥ ≤ (α → ⊥) t α

Yes, it turns out, by case analysis on α. And only by case analysis. 5

Extensibility

If a program typechecks, it should still typecheck when more types are added

This is a useful property: • New versions of the language • User-defined types • Seperate compilation 6

Do we have extensibility? (⊥ → >) → ⊥ ≤ (α → ⊥) t α

Let’s add a new type of functions τ1 subtypes of -types. Now, α = (>

⊥)

τ2 , so that →-types are

⊥ is a counterexample!

The previous reasoning relied on the non-existence of

.

7

Do we have extensibility? (⊥ → >) → ⊥ ≤ (α → ⊥) t α

Let’s add a new type of functions τ1 subtypes of -types. Now, α = (>

⊥)

τ2 , so that →-types are

⊥ is a counterexample!

The previous reasoning relied on the non-existence of

.

We need an open-world definition: τ = α|τ tτ |τ uτ |⊥|>|τ →τ 7

Avoiding the hard problems

Type inference with subtyping is traditionally considered difficult.

We have two tricks for getting around the difficulties: • Define types properly • Only use half of them

8

Avoiding the hard problems

Type inference with subtyping is traditionally considered difficult.

We have two tricks for getting around the difficulties: • Define types properly • Only use half of them

8

Input and output types τ t τ 0 : this code produces a value which is a τ or a τ 0 τ u τ 0 : this code requires a value which is a τ and a τ 0 t is only useful for outputs, and u is only useful for inputs.

9

Input and output types τ t τ 0 : this code produces a value which is a τ or a τ 0 τ u τ 0 : this code requires a value which is a τ and a τ 0 t is only useful for outputs, and u is only useful for inputs. Divide types into output types τ + and input types τ − :

τ + ::= α | τ + t τ + | ⊥ | τ − → τ + τ − ::= α | τ − u τ − | > | τ + → τ −

9

Polymorphism

Here’s a function that takes two values and returns one of them: choose : α1 → α2 → α3

10

Polymorphism

Here’s a function that takes two values and returns one of them: choose : α1 → α2 → α3 In ML, you must have α1 = α2 = α3 . With subtyping, you must have α1 ≤ α3 , α2 ≤ α3 . α1 and α2 may be incomparable.

10

Polymorphism

Here’s a function that takes two values and returns one of them: choose : α1 → α2 → α3 In ML, you must have α1 = α2 = α3 . With subtyping, you must have α1 ≤ α3 , α2 ≤ α3 . α1 and α2 may be incomparable. choose : τ1− → τ2− → τ3+

10

Cases of unification

In HM inference, unification happens in three situations: • Unifying two input types • Unifying two output types • Using the output of one expression as input to another

11

Cases of unification

In HM inference, unification happens in three situations: • Unifying two input types • Unifying two output types • Using the output of one expression as input to another We handle these as: • Introducing u • Introducing t • Decomposing a τ + ≤ τ − constraint

11

Decomposing constraints

We only need to decompose constraints of the form τ + ≤ τ − .

τ1 t τ2 ≤ τ3



τ1 ≤ τ3 , τ2 ≤ τ3

τ1 ≤ τ2 u τ3



τ1 ≤ τ2 , τ1 ≤ τ3

Thanks to the input/output type distinction, the hard cases of τ1 u τ2 ≤ τ3 and τ1 ≤ τ2 t τ3 can never come up.

12

Typechecking OCaml’s List module

Most of the OCaml List module typechecks, with the same types as OCaml (modulo syntax annoyances, and unimplemented features).

13

Questions? http://www.cl.cam.ac.uk/~sd601/mlsub [email protected]

14

15

Defining types extensibly Include variables and lattice operations in the definition of types: τ = α|τ tτ |τ uτ |⊥|>|τ →τ Define some rules about when types are equal: (τ1 → τ2 ) t (τ3 → τ4 ) = (τ1 u τ3 ) → (τ2 t τ4 ) ... This is the standard construction of a free algebra, and variables aren’t presumed to be divided into cases. (⊥ → >) → ⊥ 6≤ (α → ⊥) t α 16

Mutable references References are generally considered “invariant”. Instead, consider ref a two-argument constructor (α, β) ref with operations: make : (α, α) ref get : (⊥, β) ref → β set : (α, >) ref → α → unit

17

Suggest Documents