Dependent types Ordinary functions (T1 -> T2) G, x:T1 |- t:T2 ----------------------- G |- \x:T1.t : T1 -> T2 G |- t2 : T1 -> T2 G |- t1 : T1 ---------------------------------- G |- t2 t1 : T2 Type depends on a type G, X : Type |- t:T2 -------------------------- G |- \X.t : All X:Type. T2 G |- t1 : All X:Type. T2 G |- T1 : Type ------------------------------------------ G |- t1 [T1] : T2[X |-> T1] Type depends on a value G, x:T1 |- t:T2 --------------------------- G |- \x:T1.t : All x:T1. T2 G |- t2 : All x:T1. T2 G |- t1 : T1 -------------------------------------- G |- t2 t1 : T2[x |-> T1] Notation All x:T1. T2 Pi x:T1. T2 x:T1 -> T2 Example: All x:Nat. All y:Nat. x+y = y+x All x:Nat. x > 0 => Exists y:Nat. y^2 <= x < (y+1)^2. Notation for predicates term satisfying predicate t in X X t predicate { x:T | p } : Set T \x:T.p : T -> Prop combining and simplifying t in { x:T | p } --> p[x |-> t] (\x:T.p) t --> p[x |-> t] Leibniz equality: t1 = t2, with t1,t2:T, can be defined by \X. t1 in X -> t2 in X This is symmetric, because we can pick X to be *any* property. One property we can choose is { x : T | x = t1 }. t1 = t2 = {def'n} All X. t1 in X -> t2 in X => {instantiate X to { x : T | x = t1 }} t1 in { x:T | x = t1 } -> t2 in { x:T | x = t1 } = {simplify} t1 = t1 -> t2 = t1 = { t1 = t1 is true, simplify } t2 = t1