Principal type inference with subtyping
Stephen Dolan and Alan Mycroft April 21, 2016
Computer Laboratory University of Cambridge
Principal type inference with subtyping Stephen Dolan and Alan - - PowerPoint PPT Presentation
Principal type inference with subtyping Stephen Dolan and Alan Mycroft April 21, 2016 Computer Laboratory University of Cambridge select select p v d = if ( p v ) then v else d 2 select select p v d = if ( p v ) then v else d ML : . (
Stephen Dolan and Alan Mycroft April 21, 2016
Computer Laboratory University of Cambridge
select p v d = if (p v) then v else d
2
select p v d = if (p v) then v else d ML : ∀α.(α → bool) → α → α → α
2
select p v d = if (p v) then v else d ML : ∀α.(α → bool) → α → α → α v argument to p result d
2
select p v d = if (p v) then v else d ML : ∀α.(α → bool) → α → α → α v argument to p result d MLsub : ∀α.(α → bool) → α → β → (α ⊔ β)
2
When I add more types, no programs should break.
4
Types: τ ::= bool | τ1 → τ2 | {ℓ1 : τ1, . . . , ℓn : τn}
5
Types with subtyping: τ ::= bool | τ1 → τ2 | {ℓ1 : τ1, . . . , ℓn : τn} bool ≤ bool τ ′
1 ≤ τ1
τ2 ≤ τ ′
2
τ1 → τ2 ≤ τ ′
1 → τ ′ 2
{ℓ1 : τ1, . . . , ℓn : τn, . . . } ≤ {ℓ1 : τ1, . . . ℓn : τn} τ1 ≤ τ ′
1
. . . τn ≤ τ ′
n
{ℓ1 : τ1, . . . , ℓn : τn} ≤ {ℓ1 : τ ′
1, . . . , ℓn : τ ′ n}
5
Types with subtyping, least and greatest types: τ ::= bool | τ1 → τ2 | {ℓ1 : τ1, . . . , ℓn : τn} | ⊥ | ⊤ bool ≤ bool τ ′
1 ≤ τ1
τ2 ≤ τ ′
2
τ1 → τ2 ≤ τ ′
1 → τ ′ 2
{ℓ1 : τ1, . . . , ℓn : τn, . . . } ≤ {ℓ1 : τ1, . . . ℓn : τn} τ1 ≤ τ ′
1
. . . τn ≤ τ ′
n
{ℓ1 : τ1, . . . , ℓn : τn} ≤ {ℓ1 : τ ′
1, . . . , ℓn : τ ′ n}
⊤ ≤ τ τ ≤ ⊤
5
Types with lattice subtyping: τ ::= bool | τ1 → τ2 | {ℓ1 : τ1, . . . , ℓn : τn} | ⊥ | ⊤ bool ≤ bool τ ′
1 ≤ τ1
τ2 ≤ τ ′
2
τ1 → τ2 ≤ τ ′
1 → τ ′ 2
{ℓ1 : τ1, . . . , ℓn : τn, . . . } ≤ {ℓ1 : τ1, . . . ℓn : τn} τ1 ≤ τ ′
1
. . . τn ≤ τ ′
n
{ℓ1 : τ1, . . . , ℓn : τn} ≤ {ℓ1 : τ ′
1, . . . , ℓn : τ ′ n}
⊤ ≤ τ τ ≤ ⊤
5
F(A) = Bool(A) + Func(A) + Rec(A) Bool(A) = bool Func(A) = A × A Rec(A) = L ⇀ A Take the initial algebra of F : Set → Set
6
F(A) = Bool(A) + Func(A) + Rec(A) Bool(A) = bool Func(A) = A− × A Rec(A) = L ⇀ A Take the initial algebra of F : Pos → Pos.
6
F(A) = Bool(A) + Func(A) + Rec(A) Bool(A) = (bool)⊤
⊥
Func(A) = (A− × A)⊤
⊥
Rec(A) = (L ⇀ A)⊤
⊥
Take the initial algebra of F : Pos⊤
⊥ → Pos⊤ ⊥.
6
F(A) = Bool(A) + Func(A) + Rec(A) Bool(A) = (bool)⊤
⊥
Func(A) = (A− × A)⊤
⊥
Rec(A) = (L ⇀ A)⊤
⊥
Take a lattice of types, forget that it’s a lattice, apply F : Pos⊤
⊥ →
Pos⊤
⊥, and notice that the result happens to be a lattice.
6
F(A) = Bool(A) + Func(A) + Rec(A) Bool(A) = (bool)⊤
⊥
Func(A) = (A− × A)⊤
⊥
Rec(A) = (L ⇀ A)⊤
⊥
Take the initial algebra of F : Lat → Lat.
6
τ ::= bool | τ1 → τ2 | {ℓ1 : τ1, . . . , ℓn : τn} The | should be the coproduct. Not always union!
7
τ ::= bool | τ1 → τ2 | {ℓ1 : τ1, . . . , ℓn : τn} The | should be the coproduct. Not always union! We get some new types: (τ → τ) ⊓ {foo : τ}
7
τ ::= bool | τ1 → τ2 | {ℓ1 : τ1, . . . , ℓn : τn} The | should be the coproduct. Not always union! We get some new types: (τ → τ) ⊓ {foo : τ} ≤ bool
7
How about type variables as metavariables?
8
How about type variables as metavariables? Pottier’s tricky example: τ = ⊥ | τ → τ | ⊤ (⊥ → ⊤) → ⊥ ≤ (α → ⊥) ⊔ α This is true, by case analysis. . .
8
How about type variables as metavariables? Pottier’s tricky example: τ = ⊥ | τ → τ | ⊤ (⊥ → ⊤) → ⊥ ≤ (α → ⊥) ⊔ α This is true, by case analysis. . . until we extend the type system α = (⊤ ◦ → ⊥)
8
How about type variables as metavariables? Pottier’s tricky example: τ = ⊥ | τ → τ | ⊤ (⊥ → ⊤) → ⊥ ≤ (α → ⊥) ⊔ α This is true, by case analysis. . . until we extend the type system α = (⊤ ◦ → ⊥)
We need type variables as a free algebra. Syntactically, add them as opaque indeterminates: τ ::= bool | τ1 → τ2 | {ℓ1 : τ1, . . . , ℓn : τn} | α
8
We have lots of types, but they’re not all useful all the time. τ1 ⊔ τ2 describes an output that may be τ1 or may be τ2. τ1 ⊓ τ2 describes an input that must be τ1 and must be τ2
10
We have lots of types, but they’re not all useful all the time. τ1 ⊔ τ2 describes an output that may be τ1 or may be τ2. τ1 ⊓ τ2 describes an input that must be τ1 and must be τ2 Use positive types τ + for outputs, and negative types τ − for inputs: τ + ::= α | τ + ⊔ τ + | ⊥ | unit | τ − → τ + τ − ::= α | τ − ⊓ τ − | ⊤ | unit | τ + → τ −
10
Two inputs: introduce ⊓ Two outputs: introduce ⊔ Output used as an input: constraint τ + ≤ τ −
11
Two inputs: introduce ⊓ Two outputs: introduce ⊔ Output used as an input: constraint τ + ≤ τ − Handling ⊔ and ⊓ is easy, thanks to polarity: τ1 ⊔ τ2 ≤ τ3 iff τ1 ≤ τ3, τ2 ≤ τ3 τ1 ≤ τ2 ⊓ τ3 iff τ1 ≤ τ2, τ1 ≤ τ3
11
How do we get rid of α ≤ τ − or τ + ≤ α? Not substitution!
12
How do we get rid of α ≤ τ − or τ + ≤ α? Not substitution!
12
How do we get rid of α ≤ τ − or τ + ≤ α? Not substitution!
ML’s ∀ is more like a set comprehension. These are the same: ∀α∀β. α → β → α ∀β∀α. α → β → α because these are the same {α → β → α | α, β types} {α → β → α | β, α types}
12
It’s easy to remove constraints from set comprehensions:
13
It’s easy to remove constraints from set comprehensions: {n2 + 17 | n ∈ N, n ≥ 5}
13
It’s easy to remove constraints from set comprehensions: {n2 + 17 | n ∈ N, n ≥ 5} = {max(n, 5)2 + 17 | n ∈ N}
13
It’s easy to remove constraints from set comprehensions: {n2 + 17 | n ∈ N, n ≥ 5} = {max(n, 5)2 + 17 | n ∈ N} Thinking of type schemes as set comprehensions, we can do the same: α → α | α ≤ {isgood : bool}
13
It’s easy to remove constraints from set comprehensions: {n2 + 17 | n ∈ N, n ≥ 5} = {max(n, 5)2 + 17 | n ∈ N} Thinking of type schemes as set comprehensions, we can do the same: α → α | α ≤ {isgood : bool} = (α ⊓ {isgood : bool}) → (α ⊓ {isgood : bool})
13
It’s easy to remove constraints from set comprehensions: {n2 + 17 | n ∈ N, n ≥ 5} = {max(n, 5)2 + 17 | n ∈ N} Thinking of type schemes as set comprehensions, we can do the same: α → α | α ≤ {isgood : bool} = (α ⊓ {isgood : bool}) → (α ⊓ {isgood : bool}) = (α ⊓ {isgood : bool}) → α
13
filter good : list[{isgood : bool} ⊓ α] → list[α] things : list[{isgood : bool, x : int}]
14
filter good : list[{isgood : bool} ⊓ α] → list[α] things : list[{isgood : bool, x : int}] list[{isgood : bool}⊓α] → list[α] ≤ list[{isgood : bool, x : int}] → β
14
filter good : list[{isgood : bool} ⊓ α] → list[α] things : list[{isgood : bool, x : int}] list[α] ≤ β list[{isgood : bool, x : int}] ≤ list[{isgood : bool} ⊓ α]
14
filter good : list[{isgood : bool} ⊓ α] → list[α] things : list[{isgood : bool, x : int}] list[α] ≤ β {isgood : bool, x : int} ≤ {isgood : bool} ⊓ α
14
filter good : list[{isgood : bool} ⊓ α] → list[α] things : list[{isgood : bool, x : int}] list[α] ≤ β {isgood : bool, x : int} ≤ {isgood : bool} {isgood : bool, x : int} ≤ α
14
filter good : list[{isgood : bool} ⊓ α] → list[α] things : list[{isgood : bool, x : int}] list[α] ≤ β {isgood : bool, x : int} ≤ α
14
filter good : list[{isgood : bool} ⊓ α] → list[α] things : list[{isgood : bool, x : int}] β+ → β ⊔ list[α] α+ → α ⊔ {isgood : bool, x : int}
14
filter good : list[{isgood : bool} ⊓ α] → list[α] things : list[{isgood : bool, x : int}] β ⊔ list[α ⊔ {isgood : bool, x : int}]
14
filter good : list[{isgood : bool} ⊓ α] → list[α] things : list[{isgood : bool, x : int}] list[{isgood : bool, x : int}]
14
Questions? http://www.cl.cam.ac.uk/~sd601/mlsub stephen.dolan@cl.cam.ac.uk
15