Polymorphic types Polymorphic λ -calculus (System F) • Simply typed λ -calculus is “monomorphic”, • Extends simply-typed λ : i.e. a type has no “flexible” pieces τ ::= * | τ → τ – type syntax – expression/value syntax • "Good" programming languages have polymorphic types – typechecking rules – evaluation rules • So we'd like to capture the essense of polymorphic types in our calculus Polymorphic type syntax Polymorphic(ally typed) value syntax • Extend type syntax with a forall type • Syntax: τ ::= ... | ∀ I. τ | I E ::= … | Λ I.E | E[ τ ] V ::= … | Λ I.E • Can write types of polymorphic values: – Λ I.E is a function that, given a type τ , gives id : ∀ T. T → T back E with τ substituted for I map : ∀ T. ∀ U. (T → U) → T list → U list – Use such values by instantiating them: E[ τ ] : ∀ T. T list nil • E[ τ ] is like function application An example Another example (* fun applyTwice f x = f (f x) (* fun id x = x applyTwice:('a->'a) -> 'a -> 'a *) id:’a -> ‘a *) applyTwice = id = ΛΤ . λ x: Τ . x ΛΤ . λ f: Τ→Τ . λ x: Τ . f (f x) : ∀Τ . Τ→Τ : ∀Τ . ( Τ→Τ ) →Τ→Τ id [int] 3 → β applyTwice [int] succ 3 → β ( λ x:int. x) 3 → β ( λ f:int → int. λ x:int. f (f x)) succ 3 → β * 3 succ (succ 3) → β * 5 id [bool] → β λ x:bool. x 1
Yet another example A final example (* fun cool f = (f 3, f true) *) map = Λ T. Λ U. fix ( λ map:(T → U) → T list → U list. cool ≡ λ f:( ∀ T.T → T). (f [int] 3, f [bool] true) λ f:T → U. λ lst:T list. :( ∀ T.T → T) → (int * bool) fold (case (unfold lst) of <nil=n> => <nil=()> cool id → β <cons=r> => <cons={hd=f (#hd r), tl=map f (#tl r)}>)) (id [int] 3, id [bool] true) → β * : ∀ T. ∀ U. (T → U) → T list → U list (( λ x:int. x) 3, ( λ x:bool. x) true) → β * (3, true) map [int] [bool] isZero [3,0,5] → β * [false,true,false] • Note: ∀ inside of λ and → – Can't write this in ML; not "prenex" form • ML infers what the Λ I and [ τ ] should be – Type inference undecidable for full System F (and many interesting subsets); but decidable for ML-style polymorphism Evaluation and typing rules Various kinds of functions • Evaluation: • λ I.E is a function from values to values E ⇓ ( Λ I. E 1 ) ([I →τ ]E 1 ) ⇓ V • Λ I.E is a function from types to values –––––––––––––––––––––––––– [E-INST] (E[ τ ]) ⇓ V • What about functions from types to types ? – Type constructors like → , list, BTree • Typing: • We want them! Γ , I::Type " E : τ ––––––––––––––––– [T-POLY] • What about functions from values to types ? Γ " ( Λ I.E) : ∀ I. τ – Dependent type constructors like a way to build the Γ " E: ∀ I. τ ' type “arrays of length n”, where n is a run-time ––––––––––––––––––– [T-INST] computed value Γ " (E[ τ ]) : [I →τ ] τ ' • Pretty fancy, but would be cool Type constructors Kinds • A type describes a set of values or value constructors • What's the "type" of list ? (a.k.a. functions) with a common structure – Not a simple type, but a function from types to types τ ::= int | τ 1 → τ 2 | … • A kind describes a set of types or type constructors with • e.g. list(int) = int_list a common structure – There are lots of type constructors that take a single κ ::= * | κ 1 ⇒ κ 2 type and return a type As in the s.t. λ calculus, * is the “base kind” • They all have the same "meta-type" • Write τ :: κ to say that a type τ has kind κ – Other things take two types and return a type: int :: * int → int :: * • e.g. → , assoc_list list :: * ⇒ * • A "meta-type" is called a kind list int :: * assoc_list :: * ⇒ * ⇒ * assoc_list string int :: * 2
Kinded polymorphic λ -calculus Examples ( System F ω ω ) ω ω pair = • Full syntax: λ τ T::*. λ τ U::*. {first:T, second:U} :: * ⇒ * ⇒ * κ κ κ ::= * | κ κ κ κ κ 1 ⇒ ⇒ ⇒ ⇒ κ κ κ 2 κ pair int bool " → β " {first:int, second:bool} τ ::= int | τ 1 → τ 2 | ∀ I :: κ κ . τ | I | λ κ κ λ λ τ λ τ I:: κ κ κ κ . τ τ τ τ | τ τ τ 1 τ τ τ τ 2 τ τ τ E ::= λ I: τ . E | I | E 1 E 2 | Λ I :: κ κ .E | E[ τ ] {first=5, second=true} : pair int bool κ κ V ::= λ I.E | Λ I :: κ κ .E κ κ swap = Λ P::type ⇒ type ⇒ type. Λ T::*. Λ U::* . – Functions and applications at both the value λ p:P T U . {first=#second p, second=#first p} and the type level : ∀ P::* ⇒ * ⇒ *. ∀ T::*. ∀ U::*. P T U → P U T – Arrows at both the type and kind level swap [pair] [int] [bool] ... Expression typing rules Type kinding rules Γ " τ 1 ::* Γ , I: τ 1 " E: τ 2 Γ " τ 1 :: * Γ " τ 2 :: * –––––––––––––––––––––––– [T-ABS] Γ " ( λ I: τ 1 . E) : τ 1 → τ 2 –––––––––––– [K-INT] ––––––––––––––––––––––––– [K-ARROW] Γ " int :: * Γ " ( τ 1 → τ 2 ) :: * Γ , I:: κ " E: τ ––––––––––––––––––––– [T-POLY] Γ " ( Λ I:: κ .E) : ∀ I:: κ . τ Γ , I:: κ " τ :: * I:: κ ∈ Γ –––––––––––––––––– [K-FORALL] –––––––––– [K-VAR] Γ " E : ∀ I:: κ . τ ' Γ " τ :: κ Γ " ( ∀ I:: κ . τ ) :: * Γ " I:: κ ––––––––––––––––––––––––– [T-INST] Γ " (E[ τ ]) : [I →τ ] τ ' Γ , I:: κ 1 " τ :: κ 2 Γ " τ 1 :: κ 2 → κ 1 Γ " τ 2 :: κ 2 ––––––––––––––––––––– [K-ABS] –––––––––––––––––––––––– [K-APP] (T-VAR and T-APP unchanged) Γ " ( λ τ I:: κ 1 . τ ) :: κ 1 → κ 2 Γ " ( τ 1 τ 2 ) :: κ 1 Higher-order kinds? Phase distinction • Could “lift” polymorphism to type level... • Could also collapse all levels of language down to one: κ ::= … | ∀ I. κ | Ι E ::= I | λ I:E.E | E 1 E 2 τ ::= … | Λ τ I:: κ . τ | κ [ τ ] • Could “lift” meta-kinding to kind level… • Loses phase distinction between run-time and typecheck-time M ::= * | M ⇒ M – Fundamental to achieving benefits of type systems κ ::= … | λ κ I::M. κ | κ 1 κ 2 – (More generally, might be desirable to have many phases: compile, link, initialize, run, etc.; could use • …and so on to arbitrary “tower” of meta- meta-levels in language to encode these phase levels of language distinctions.) 3
Summary Other uses • Saw ever more powerful static type systems for • Compiler internal representations for the λ -calculus advanced languages – Simply typed λ -calculus – E.g. FLINT: compiles ML, Java, … – Polymorphic λ -calculus, a.k.a. System F • Checkers for interesting non-type – Kinded poly. λ -calculus, a.k.a. System F ω properties, e.g.: • Exponential ramp-up in power, once build up sufficient critical mass – proper initialization • Real languages typically offer some of this – static null pointer dereference checking power, but in restricted ways – safe explicit memory management – Could benefit from more expressive approaches – thread safety, data-race freedom 4
Recommend
More recommend