Subtyping and the Penn interpretation Philip Wadler, 7 March 2008 Simply-typed lambda calculus with records and subtyping ------------------------------------------------------- Terms [var] (x : T) in G ------------ G |- x : T [abs] G, x : T1 |- t2 : T2 --------------------- G |- \x.t2 : T1 -> T2 [app] G |- t1 : T1 -> T2 G |- t2 : T1 ---------------------------------- G |- t1 t2 : T2 [rec] G |- t1 : T1 ... G |- tn : Tn ----------------------------------------- G |- (l1=t1,...,ln=tn) : (l1=T1,...ln=Tn) [fld] G |- t : (l1=T1,...ln=Tn) ------------------------- G |- t.li : Ti [sub] G |- t : T1 T1 <: T2 ----------------------- G |- t : T2 Subtypes [refl] ------ T <: T [tran] S <: T T <: U ---------------- S <: U [top] -------- T <: Top [fun] S' <: S T <: T' ------------------ S -> T <: S' -> T' [width] ------------------------------------------------ where m < n (l1:T1,...,lm:Tm,...,ln:Tn) <: (l1:T1,...,lm:Tm) [depth] S1 <: T1 ... Sn <: Tn -------------------------------------- (l1:S1,...,ln:Sn) <: (l1:T1,...,ln:Tn) Penn interpretation ------------------- Source: simply-typed lambda calculus with records and subtyping; as above. Target: simply-typed lambda calculus with records and *no* subtyping; as above, without rule [sub] or the subtyping rules. The translation is derivation-directed: the input is a type-derivation in the source, rather than a term in the source. Term derivations translate into terms: G |- t : T --> t' (source) implies G |- t' : T (target) [var] (x : T) in G ---------------- G |- x : T --> x [abs] G, x : T1 |- t2 : T2 --> u2 ------------------------------------- G |- \x:T1.t2 : T1 -> T2 --> \x:T1.u2 [app] G |- t1 : T1 -> T2 --> u1 G |- t2 : T1 --> u2 ------------------------------------------------ G |- t1 t2 : T2 --> u1 u2 [rec] G |- t1 : T1 --> ui ... G |- tn : Tn --> un ----------------------------------------------------------------- G |- (l1=t1,...,ln=tn) : (l1=T1,...ln=Tn) --> (l1=u1,...,ln = un) [fld] G |- t : (l1=T1,...ln=Tn) --> u ------------------------------- G |- t.li : Ti --> u.li [sub] G |- t : T1 --> u T1 <: T2 --> c ----------------------------------- G |- t : T2 --> c u Subtype derivations translate into coercions: S <: T --> c (source) implies |- c : S -> T (target) [refl] ------------- T <: T --> id id = \x:T.x [tran] S <: T --> c T <: U --> d ---------------------------- S <: U --> d.c where composition is defined by d.c = \x:S.d(c(x)) [fun] S' <: S --> c T <: T' --> d ------------------------------- S -> T <: S' -> T' --> c -> d where the function operator on coercions is defined by: c -> d = \f:S->T. \x:S'. d(f(c(x))) or, equivalently: (c -> d) f = d . f . c [width] ------------------------------------------------ where m < n (l1:T1,...,lm:Tm,...,ln:Tn) <: (l1:T1,...,lm:Tm) --> \r:(l1:T1,...,lm:Tm,...,ln:Tn).(l1=r.l1,...,lm=r.lm) [depth] S1 <: T1 --> c1 ... Sn <: Tn --> cn ------------------------------------------------ (l1:S1,...,ln:Sn) <: (l1:T1,...,ln:Tn) --> \r:(l1:S1,...,ln:Sn).(l1=c1(r.l1),...,ln=cn(r.ln)) Coherence --------- Sometimes a term will have more than one type derivation. All derivations of the same term must have equivalent meanings. Example 1. Coherence of the subsumption rule. G |- s : S --> s' S <: T --> c -------------------------------- G |- s : T --> c(s') T <: U --> d ---------------------------------------------- G |- s : U --> d(c(s')) S <: T --> c T <: U --> d ---------------------------- G |- s : S --> s' S <: U --> d.c ----------------------------------- G |- s : U --> (d.c)(s') As required for coherence, we have: d(c(s')) = (d.c)(s') Example 2. Coherence of function subtyping and transitivity. T1 <: S1 --> c1 S2 <: T2 --> c2 U1 <: T1 --> d1 T2 <: U2 --> d2 ---------------------------------- --------------------------------- S1->S2 <: T1->T2 --> c1->c2 T1->T2 <: U1->U2 --> d1->d2 ----------------------------------------------------------------- S1->S2 <: U1->U2 --> (d1->d2).(c1->c2) U1 <: T1 --> d1 T1 <: S1 --> c1 S2 <: T2 --> c2 T2 <: U2 --> d2 ---------------------------------- --------------------------------- U1 <: S1 --> c1.d1 S2 <: U2 --> d2.c2 ----------------------------------------------------------------- S1->S2 <: U1->U2 --> (c1.d1)->(d2.c2) As required for coherence, we have: ((d1->d2).(c1->c2))(f) = d2.c2.f.d1.c1 = (c1.d1)->(d2.c2)(f)