CS 641 Lecture -*- Outline -*- typographical convention: \ below means \lambda in LaTeX, all means \forall, poly is \Lambda, [x:A]B is \Pi x:A . B, & is \times (cross product), ... * Explicit type systems (refer to Barandregt and Hemerik's "Types in Lambda Calculi and Programming Languages", LNCS 432) dependencies (aspects of calculus of constructions): elements depend on elements (simply typed) elements depend on types (\2, SOL, Girard-Reynolds) e.g., \x:s.x, sort[t] types depend on types (\-omega_, weakly higher order \-calc) e.g., list[t] types depend on elements (dependent types, \P) e.g., IntArray[1,3] all properties hold for all the systems e.g, strong normalization, unicity of types, decidability of type checking ** Curry-Howard Isomorphism, Propositions as Types ---------------------------- proposition ~~ type constructive proof ~~ term in a typed lambda calculus (evidence) (algorithm) ---------------------------- e.g., A ==> (B ==> A) is like the type A -> (B -> A) proof: if a is a proof of A, and b is a proof of B, then (B ==> A) is true, by the proof a term: \a:A . \b:B . a types can also be thought of as tasks or problem statements (Kolmogorov and Martin-Lof) *** Higher-order logic order of function type: order(b) = 0, where b is a base type order(t->s) = 1 + max(order(t),order(s)) --------------------- order formulae quantif over 0 x 1 all x:T . P T 2 all P . all x:T . P T -> T 3 all double . all f . all x . P(double(f)(x)) (T->T)->(T->T) --------------------- *** Higher-order programming --------------------- order terms arg. types 0 x 1 \x:T . P T 2 \P:* . \x:T . P * -> * 3 \double . \f . \x . P(double(f)(x)) (*->*)->(*->*) --------------------- analogous proof rules for each level of quantification (abstraction) ** \2-Church, SOL, Girard-Reynolds calculus, system F (i.e., F2) elements can depend on types (but not types on types) polymorphic functions are first-class objects! ------------------- T ::= V | C | T -> T | all V . T e ::= v | c | e e | e T | \ v:T . e | poly V . e ------------------- e.g., (poly t. \x:t . x) : all t . t -> t some authors write e[T] for appliation to a type to distinguish from ordinary application counterexample: poly s. all t . t -> t types are not expressions (types cannot depend on types) counterexample: \x:num . all t . t -> t types cannot depend on elements *** rules see page 21 give examples and counter-examples *** pragmatics amazing expressive power (esp. for data structures) **** representability ***** some total recursive functions not expressible e.g., normalization ***** can express provably total functions in 2nd order peano arithmetic **** type defs type t = tau desugars to (poly t . e) e tau **** abstract data types (as in CLU or ML abstypes) (page 22) defined by giving concrete representation and operations (see page 22) ***** booleans (coding due to Church) --------------------- let bool = all T . T -> T -> T true : bool = poly T . \x:T . \y:T . x false : bool = poly T . \x:T . \y:T . y if: all T.bool->T->T->T = poly T . \b:bool . \e1:T . \e2:T . b T e1 e2 --------------------- note: bool is not an object (it has no type). bool has only 2 elements exercise: prove |- true: bool exercise: show |- if num true 3 4 : num ***** products (due to Pradwitz) --------------------- let (& U V) = all T . (U -> V -> T) -> T pair = poly U . poly V . \u:U . \v:V . poly T . \f:(U->V->T) . f u v fst = poly U . poly V . \p:(& U V) . p U (\f:U . \s:V . f) snd = poly U . poly V . \p:(& U V) . p V (\f:U . \s:V . s) --------------------- (& U V) is syntactic sugar, as & is not expressible in \2 & is used because this is logically "and" exercises: what is (pair Int Bool 3 true)? use beta rules show |- (pair Int Bool 3 true) : (& Int Bool) what is (snd Int Bool) (pair Int Bool 3 true) show |- (snd Int Bool) (pair Int Bool 3 true) : Bool ***** sums coding from Girard-LaFont-Taylor --------------------- let (+ U V) = all T . (U -> T) -> (V -> T) -> T inl = poly U . poly V . \u:U . poly T . \l:U->T . \r:V->T . l u inr = poly U . poly V . \v:V . poly T . \l:U->T . \r:V->T . r v cases = poly U . poly V . \x:(+ U V) . x --------------------- exercises: what is (inr Int Bool true)? show |- (inr Int Bool true) : (+ Int Bool) what is (cases Int Bool) (inr Int Bool)? show |- (cases Int Bool) (inr Int Bool) : (+ Int Bool) what is (inr Int Bool) Color (\x:Int.green) (\y:Bool.red)? show H |- (inr Int Bool) Color (\x:Int.green) (\y:Bool.red) : Color where H == green:Color, red:Color ***** etc. general pattern ---------------------- name constructors type bool true:bool all T . T -> false: bool T -> T (& U V) pair:U -> V -> (& U V) all T . (U -> V -> T) -> T (+ U V) inl:U -> (+ U V), all T . (U -> T) -> inr:V -> (+ U V) (V -> T) -> T ---------------------- e.g., natural numbers, finite lists, existential types, trees, ... there is a general construction for all inductive types (see Girard-LaFont-Taylor 11.4-11.5) **** relation to ML in ML cannot type check (\f.(f 3, f true))(\x.x) in \2, can do this (\f:(all t. t->t) . (f num 3, f bool true))(poly t. \x:t . x) so ML is less expressive than a full second-order system polymorphic functions are first-class objects in \2 (not ML) ** \-omega_ (lambda-omega-underbar) types can depend on types constructors (e.g., ->, array) as objects e.g., & and + from above e.g., matrix = double array have a kind-checking problem, using types properly *** Kinds ------------------------- * is the kind of types (set of all types) so t: * means t is a type (has kind *) * -> * is a constructor (maps types to types) K ::= * | K -> K ------------------------- e.g., product construtor: &: *->*->*->* sum constuctor: +: *->*->*->* double: (*->*) -> *->* [] is the set of all kinds so k: [] means k is a kind. *** Syntax and rules see pages 23 and 24 ------------------------------- e ::= V | C | e e | \ V:e . e | e -> e C ::= * | [] | ... ------------------------------- note rules really restrict this syntax esp ->I and type/kind formation is *->T a type or a kind (or nothing)? is T:* |- (* -> T):? derivable is [] -> [] a type/kind? **** no mixing of kinds and types (elements cannot depend on types) nothing corresponding to poly no polymorphic elements, elements don't depend on types (have to look at rules to see this) the pseudoterm \T:* . \x:T . x has no type/kind as * -> (T -> T) is not well-formed (problem: matching T with initial argument). (\T:* . T -> T) is a parameterized verions of -> e.g., endomorph = (\T:*.T -> T) : (* -> *) \x:nat.x : endomorph(nat) pair = \U:*\V:*.\u:U.\v:V.\T:*.\f:(U->V->T).f u v has no type or kind as *->*->U->.... is not well formed **** types can depend on types & = \U:*.\V:*.\T:*.(U -> V -> T) -> T + = \U:*.\V:*.\T:*.(U -> T) -> (V -> T) -> T +: *->*->*->* an example used below ---------------------------------- |- *:[], |- *:[] axiom, axiom _____________________________ type/kind formation |- *:[], |- *->*:[] axiom (on left) _____________________________ type/kind formation |- *->(*->*):[] _____________________________ weakening U:* |- (*->*->*):[] ---------------------------------- the & constructor ---------------------------------- |- *:[] axiom ________________________ weakening U:*, V:*, T:* |- *:[] ___________________________________________ start U:*, V:*, T:* |- V:*, U:*, V:*, T:* |- T:* _________________________________________________ t/k formation U:*, V:*, T:* |- U:*, U:*, V:*, T:* |- (V -> T):* _______________________________________________________ t/k formation U:*, V:*, T:* |- (U -> V -> T):*, U:*, V:*, T:* |- T:* ___________________________________________ type/kind formation U:*, V:* |- *:[], U:*, V:*, T:* |- *:[], U:*, V:*, T:* |- ((U -> V -> T) -> T) : * ___________________________________________ (->I) U:* |- *:[], U:*, V:* |- *->* : [], U:*, V:* |- (\T:*.(U -> V -> T) -> T) : * -> * ___________________________________________ (->I) |- *:[], U:* |- (*->*->*):[], U:* |- (\V:*.\T:*.(U -> V -> T) -> T) : * -> * -> * ________________________________________________________ (->I) |- (\U:*.\V:*.\T:*.(U -> V -> T) -> T) : * -> * -> * -> * ---------------------------------- e.g., double = \k:*->* . \t:* . k(k t) double: (*->*)->*->* array:*->* play with the examples in 4.2.6 why are normal forms for types important? *** pragmatics can compute on types can define constructors constructors are first-class objects e.g., bool, &, + above can be passed to functions, returned, etc. but no polymorphic functions, no polymorphic abstract types! e.g. polymorphic identity, polymorphic pairing function... advantages of constructions: can explain polymorphic type declarations using let don't need 2 kinds of declarations can treat constructors like array as objects **** \omega union of \2 (elements depending on types) and \-omega_ (types on types) allows full treatment of the & and + examples. the story so far: \2: polymorphic elements (poly T. \x:T . x) no type constructors (& cannot be defined) sum: elements depend on types \-omega_ no polymorphic elements! type constructors sum: types depend on types ***** problem (page 26 at top): in \-omega_ can declare & and + but not their opertions in \2 can declare operations of & and + but not & and + themselves ------------------------------------------------- num:*, 0:num |- (*->*):[], (axioms, t/k form) num:*, 0:num, a:(*->*) |- num:[] invalid! num:*, 0:num, a:(*->*) |- 0:num (start, weakening) _____________________________________ ->I num:*, 0:num |- (\a:*->*.0) : (*->*)->num, num:*, 0:num |- (\b:*.b->b): (*->*) (ignore this) _____________________________________ ->E num:*, 0:num |- (\a:*->*.0)(\b:*.b->b) : num ------------------------------------------------- ** \P (logical framework, LF) types can depend on elements (but not types) e.g., Intarray[3,4] T a type, k a kind, then T -> k is a kind e.g, if f: T -> *, and x:T, then f(x) : * is a dependent type e.g., (\n:Nat) if (equal n 0) then true else 3 graph: {(0, true), (1,3), (2,3), ...} type: [n:Nat] if (equal n 0) then Bool else Nat function types expressed (represented) using indexed products let A and B be expressions defining collections (sets), where B hasd a free variable x of type A [x:A]B is the cartesian product of the family {B(x) | x in A}, with elements functions f s.t. f(a) in [a/x]B [x:A]B can be thought of as an indexed set {B(x)}_{x in A}, and an indexed set is a function f: (a:A) -> [a/x]B where the result domain is partly determined by the argument. if x does not affect B, then [x:A]B is just A -> B. *** syntax notation used below from Coquand and Huet's paper (on calc of constrs) ---------------------- e ::= V | C | e e | (\V:e)e | [V:e]e C ::= * | [] | ... ---------------------- \ is now generalized abstraction mechanism [v:T]S is generalized arrow type (dependant arrow or product) **** abbreviation: A -> B abbreviates [x:A] B, if x not free in B. so A->* denotes [x:A] * *** rules see page 27 esp type/kind formation, ->I is * -> Nat a type? compare with page 24 no constructors, (see type/kind form rule) cannot form product types whose arg is a type (types cannot depend on types) no polymorphic elements (see ->I rule) no way to write poly T . \x:T . x play with examples e.g., ones in 4.3.3 counter-example: the above if stuff? *** pragmatics, formalization of constructive math (page 28) ---------------------- * is set of valid propositions (truth) A => B translated A -> B \forall x:A . Px translated [x:A] Px predicate P on A translated P : A -> * ---------------------- **** a formula is valid if its translation into a type has elements element = terms with that type this is the key point in understand the relationship between propositions and types e.g., A => (B => A) valid, the type A -> (B -> A) has elements (see below) counter: A => (A => B) invalid, no terms with type A -> (A -> B), in empty context (where no constants of type B) **** an element is a constructive proof of a formula ------------------------------- proof of A => (B => A) translation A -> (B -> A) : * proofs: (\x:A) (\y:B) x : A -> (B -> A) proof of (forall x:A . Px => Qx) => (forall x:A .Px => forall x:A . Qx) translation ([x:A] (Px -> Qx)) -> ([x:A]Px) -> [x:A]Qx proof: (\f:([x:A] (Px -> Qx))) (\g:[x:A]Px) (\x:A) (f x (g x)) has the above type Even : Nat -> * = (\n:Nat)[P:(Nat -> *)] ([u:Nat] P (2 u)) -> (P n) logically: (Even n) is forall P . (forall u:Nat . P (2 u)) => P n Multof4 : Nat -> * = (\n:Nat)[P:(Nat -> *)] ([u:Nat] P (2 (2 u))) -> (P n) proof of forall x:Nat . Multof4 x => Even x translation [x:Nat] (Multof4 x) -> (Even x) proof: (\x:Nat) (\a:(Multof4 x)) (\P:(Nat -> *)) (\D:([u:Nat] (P (2 u)))) (a P ((\u:Nat) D (2 u))) ------------------------------- other examples: predicate <, subrange types, ... ** Generalized type systems, \P-omega (calculus of constructions) unified way to describe refinements of \P-omega idea is to control which abstractions are allowed. *** Syntax ------------------------- e ::= V | C | e e | (\V:e)e | [V:e]e ------------------------- *** rules **** specification = (S,A,R) S subset of C (sorts), e.g., * and [] A set of axioms of form c:s, c in C, s in S R set of rules of form (s1,s2), with s1,s2 in S **** general rules see page 29 the rules R affect \prod-formation and \prod-introduction consider the cases where (in addition to (*,*)) ([],*) in R \2 ([],[]) in R \-omega_ ([],*) and ([],[]) in R \-omega (*,[]) in R \P \P-omega compare to the various presentations given before note that there are other systems we haven't/won't discuss (page 32) *** examples **** examples in \-omega ---------------------- Nat : * = [A:*][zero: A][succ: A -> A] A 0 : Nat = (\A:*)(\zero: A)(\succ: A -> A) zero S : Nat -> Nat = (\n:Nat)(\A:*)(\zero: A)(\succ: A -> A) (succ (n A zero succ)) It : [A:*](A->A)->Nat->A->A = (\A:*)(\f:A->A)(\n:Nat)(\u:A) n A u f mult: Nat -> Nat = ... 2 : Nat -> Nat = (\n:Nat)(\A:*)(\zero: A)(\succ: A -> A) (mult (succ (succ zero)) n) ----------------------- --------------------- ([T:*] (U -> V -> T) -> T) : * note that ([],*) in rules for \-omega & : [U:*][V:*] * = (\U:*)(\V:*)[T:*] (U -> V -> T) -> T pair : [U:*][V:*] U -> V -> (& U V) = (\U:*)(\V:*)(\u:U)(\v:V)(\T:*)(\f:(U->V->T)) f u v fst = (\U:*)(\V:*)(\p:(& U V)) p U ((\f:U)(\s:V) f) snd = (\U:*)(\V:*)(\p:(& U V)) p V ((\f:U)(\s:V) s) Compose : [A:*][B:*][C:*][f:A->B][g:B->C] A -> C = (\A:*)(\B:*)(\C:*)(\f:A->B)(\g:B->C)(\x:A) g (f x) --------------------- note: pair is proof of it's type (think of & as "and") what is expanded type of pair? what are the types of fst and snd? **** examples in \P-omega ***** types are first-class citizens as in \-omega, but can now depend on elements ------------------------------- -> : [A:*][B:*] * = (\A:*)(\B:*)[x:A]B Pi : [A:*][B:[u:A]*] * = (\A:*)(\B:[u:A]*)[x:A] B x elminPi : [A:*][B:*][a:A] (Pi A B) -> (B a) = (\A:*)(\B:*)(\a:A)(\p:(Pi A B)) p a introPi : [A:*][B:*][C:*][f:[x:A] (C -> (B x))] (C -> (Pi A B)) = (\A:*)(\B:*)(\C:*)(\f:[x:A](C->(B x)))(\c:C)(\a:A)(f a c) ------------------------------- how does (Pi A B) differ from [x:A]B ? properties: elminPi A b a f = f a introPi A B C (\x:A.\y:c.g x y) c = \a:A.g a c ***** types are propositions more properly, functions into * are propositions ------------------- let A:* in Id : A -> A -> * = (\x:A)(\y:A)[P:(A -> *)] (P x) -> (P y) IdIsReflexive : * = [x:A] Id x x ProofOfAbove : IdIsReflexive = (\x:A)(\P:(A -> *))(\p:(P x)) p ------------------- counterexample: the type \bot = [A:*]A has no elements give all the proofs of [A:*] A -> A -> A what is [A:*] A -> A -> A? ***** type structure is very fine ----------------------- EvenNats : * = Sum n:Nat . (Even n) EvenNatPair : * = (& EvenNats EvenNats) EqualNatPair : * = [p:(& Nat Nat)][Q:(Nat -> Nat -> *)] (Q 0 0) -> ([u:Nat][v:Nat] (Q u v) -> (Q (S u) (S v))) -> (Q (fst Nat Nat p) (snd Nat Nat p)) ---------------------- (Not sure the above are right...) Define EqualNatPair using Id (above)? How to define EqualEvenNatPair? ***** all well-typed programs terminate can use higher-order iteration principles(not illustrated) ---------------------------- Factit : (& Nat Nat) -> (& Nat Nat) = (\z:(& Nat Nat)) (pair Nat Nat (S (fst Nat Nat z)) (mult (S (fst Nat Nat z)) (snd Nat Nat z))) fact : Nat -> Nat = (\n:Nat) (snd Nat Nat (n (Nat->Nat) Factit (pair Nat Nat 0 (S 0)))) ---------------------------- objects often carry the appropriate proofs of properties with them --------------------- partial : [n:Nat] EvenNats -> (Even n) = (\n:Nat) (\m:[x:Nat](Even x)) (m n Even ((\u:Nat) m (2 u))) ------------------- *** properties (page 31) not that all refinements of \P-omega are SN, etc. SN terms in \P-omega are provably total in w-order logic (HOL) can express domains in ways that are non-obvious type checking is decidable because type constructors are esssentially only written in the simply typed lambda calculus