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 : ∀ α. ( α → bool) → α → α → α 2
select select p v d = if ( p v ) then v else d ML : ∀ α. ( α → bool) → α → α → α v d argument to p result 2
select select p v d = if ( p v ) then v else d ML : ∀ α. ( α → bool) → α → α → α v d argument to p result MLsub : ∀ α. ( α → bool) → α → β → ( α ⊔ β ) 2
Defining types
Extensibility When I add more types, no programs should break. 4
Constructing types syntactically Types: τ ::= bool | τ 1 → τ 2 | { ℓ 1 : τ 1 , . . . , ℓ n : τ n } 5
Constructing types syntactically Types with subtyping: τ ::= bool | τ 1 → τ 2 | { ℓ 1 : τ 1 , . . . , ℓ n : τ n } τ ′ τ 2 ≤ τ ′ 1 ≤ τ 1 2 τ 1 → τ 2 ≤ τ ′ 1 → τ ′ bool ≤ bool 2 { ℓ 1 : τ 1 , . . . , ℓ n : τ n , . . . } ≤ { ℓ 1 : τ 1 , . . . ℓ n : τ n } τ 1 ≤ τ ′ τ n ≤ τ ′ . . . 1 n { ℓ 1 : τ 1 , . . . , ℓ n : τ n } ≤ { ℓ 1 : τ ′ 1 , . . . , ℓ n : τ ′ n } 5
Constructing types syntactically Types with subtyping, least and greatest types: τ ::= bool | τ 1 → τ 2 | { ℓ 1 : τ 1 , . . . , ℓ n : τ n } | ⊥ | ⊤ τ ′ τ 2 ≤ τ ′ 1 ≤ τ 1 2 τ 1 → τ 2 ≤ τ ′ 1 → τ ′ bool ≤ bool 2 { ℓ 1 : τ 1 , . . . , ℓ n : τ n , . . . } ≤ { ℓ 1 : τ 1 , . . . ℓ n : τ n } τ 1 ≤ τ ′ τ n ≤ τ ′ . . . 1 n { ℓ 1 : τ 1 , . . . , ℓ n : τ n } ≤ { ℓ 1 : τ ′ 1 , . . . , ℓ n : τ ′ n } ⊤ ≤ τ τ ≤ ⊤ 5
Constructing types syntactically Types with lattice subtyping: τ ::= bool | τ 1 → τ 2 | { ℓ 1 : τ 1 , . . . , ℓ n : τ n } | ⊥ | ⊤ τ ′ τ 2 ≤ τ ′ 1 ≤ τ 1 2 τ 1 → τ 2 ≤ τ ′ 1 → τ ′ bool ≤ bool 2 { ℓ 1 : τ 1 , . . . , ℓ n : τ n , . . . } ≤ { ℓ 1 : τ 1 , . . . ℓ n : τ n } τ 1 ≤ τ ′ τ n ≤ τ ′ . . . 1 n { ℓ 1 : τ 1 , . . . , ℓ n : τ n } ≤ { ℓ 1 : τ ′ 1 , . . . , ℓ n : τ ′ n } ⊤ ≤ τ τ ≤ ⊤ 5
What’s going on here? 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
What’s going on here? 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
What’s going on here? 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
What’s going on here? 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
What’s going on here? 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
Coproducts τ ::= bool | τ 1 → τ 2 | { ℓ 1 : τ 1 , . . . , ℓ n : τ n } The | should be the coproduct. Not always union! 7
Coproducts τ ::= bool | τ 1 → τ 2 | { ℓ 1 : τ 1 , . . . , ℓ n : τ n } The | should be the coproduct. Not always union! We get some new types: ( τ → τ ) ⊓ { foo : τ } 7
Coproducts τ ::= bool | τ 1 → τ 2 | { ℓ 1 : τ 1 , . . . , ℓ n : τ n } The | should be the coproduct. Not always union! We get some new types: ( τ → τ ) ⊓ { foo : τ } ≤ bool 7
Type variables How about type variables as metavariables ? 8
Type variables How about type variables as metavariables ? Pottier’s tricky example: τ = ⊥ | τ → τ | ⊤ ( ⊥ → ⊤ ) → ⊥ ≤ ( α → ⊥ ) ⊔ α This is true, by case analysis . . . 8
Type variables How about type variables as metavariables ? Pottier’s tricky example: τ = ⊥ | τ → τ | ⊤ ( ⊥ → ⊤ ) → ⊥ ≤ ( α → ⊥ ) ⊔ α This is true, by case analysis . . . until we extend the type system α = ( ⊤ ◦ ◦ → ⊥ ) → ⊥ 8
Type variables 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
Inferring types
Polarity 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
Polarity 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
When does ML unify? Two inputs : introduce ⊓ Two outputs : introduce ⊔ Output used as an input : constraint τ + ≤ τ − 11
When does ML unify? 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
Atomic constraints How do we get rid of α ≤ τ − or τ + ≤ α ? Not substitution! 12
Atomic constraints How do we get rid of α ≤ τ − or τ + ≤ α ? Not substitution! ∀ � = Λ 12
Atomic constraints 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
Preserving the set of instances It’s easy to remove constraints from set comprehensions: 13
Preserving the set of instances It’s easy to remove constraints from set comprehensions: { n 2 + 17 | n ∈ N , n ≥ 5 } 13
Preserving the set of instances It’s easy to remove constraints from set comprehensions: { n 2 + 17 | n ∈ N , n ≥ 5 } = { max( n , 5) 2 + 17 | n ∈ N } 13
Preserving the set of instances It’s easy to remove constraints from set comprehensions: { n 2 + 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
Preserving the set of instances It’s easy to remove constraints from set comprehensions: { n 2 + 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
Preserving the set of instances It’s easy to remove constraints from set comprehensions: { n 2 + 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
Example filter good : list[ { isgood : bool } ⊓ α ] → list[ α ] things : list[ { isgood : bool , x : int } ] 14
Example filter good : list[ { isgood : bool } ⊓ α ] → list[ α ] things : list[ { isgood : bool , x : int } ] list[ { isgood : bool }⊓ α ] → list[ α ] ≤ list[ { isgood : bool , x : int } ] → β 14
Example filter good : list[ { isgood : bool } ⊓ α ] → list[ α ] things : list[ { isgood : bool , x : int } ] list[ α ] ≤ β list[ { isgood : bool , x : int } ] ≤ list[ { isgood : bool } ⊓ α ] 14
Example filter good : list[ { isgood : bool } ⊓ α ] → list[ α ] things : list[ { isgood : bool , x : int } ] list[ α ] ≤ β { isgood : bool , x : int } ≤ { isgood : bool } ⊓ α 14
Example filter good : list[ { isgood : bool } ⊓ α ] → list[ α ] things : list[ { isgood : bool , x : int } ] list[ α ] ≤ β { isgood : bool , x : int } ≤ { isgood : bool } { isgood : bool , x : int } ≤ α 14
Example filter good : list[ { isgood : bool } ⊓ α ] → list[ α ] things : list[ { isgood : bool , x : int } ] list[ α ] ≤ β { isgood : bool , x : int } ≤ α 14
Example filter good : list[ { isgood : bool } ⊓ α ] → list[ α ] things : list[ { isgood : bool , x : int } ] β + �→ β ⊔ list[ α ] α + �→ α ⊔ { isgood : bool , x : int } 14
Example filter good : list[ { isgood : bool } ⊓ α ] → list[ α ] things : list[ { isgood : bool , x : int } ] β ⊔ list[ α ⊔ { isgood : bool , x : int } ] 14
Recommend
More recommend