460 likes | 593 Views
This presentation introduces the concept of higher-order modules and the phase distinction in type systems. It discusses the limitations and strengths of HM86, which utilizes dependent types for module modeling but struggles with type equality and checking. A new calculus, lML, is proposed, focusing exclusively on module structures without abstraction. The talk details compile-time type-checking methods and the significance of phase distinction regarding type and term equality, ultimately leading to a definitional extension to full module calculi. The work emphasizes decidability in compile-time judgments.
E N D
Higher-Order Modules and the Phase Distinction Harper, Mitchell, Moggi Presented by Aleksey Kliger Fall Semester, 2002
Motivation • HM86 introduces dependent types for modeling modules • Too powerful: type equality depends on value equality • Not clear how to statically typecheck
HMM outline • Introduce lML a simple calculus with the phase distinction property. No modules. • Extend to lMLstr , a simple structures-only calculus • Show that the full module calculus lMLmod is a definitional extension of lMLstr by a novel interpretation of dependent types • Focused on compile-time type checking, not concerned with abstraction,generativity,etc.
Phase distinction • “compile-time” vs “run-time” • Separate equality of types from equality of terms • For practical applications, want compile-time judgments to be decidable (reduces to want type equality to be decidable)
First cut: No modules • lML is similar to core-ML • Parameterized by a collection of equational axioms on terms • Comes equipped with a theorem that it can be typechecked at compile-time • Forms the definition for what it means to be checkable at compile-time
lML constuctor-level k2kind ::= 1 | T | k1£k2 | k1!k2 u2constr ::= v | ¤ | £ | ! | 1 | hu1, u2i| pi(u) | (lv:k.u) | u1u2 • Constructors-as-data • Essential for later development that we have product and function kinds
lML term-level s 2type ::= 1 | set(u) | s1£s2 | s1!s2 | (8v:k.s) e2term ::= x | ¤ | he1, e2i | pi(e) | (lx:s.e) | e1e2 | (Lv:k.e) | e[u] F2context ::= ; | F, u:k | F, x:s
F context FÀu : k Àstype FÀe : s FÀu1 = u2 : k FÀs1 = s2type FÀe1 = e2 : s lML judgments
Intersting lML term equality judgments Usual b and h rules for unit, product and sums We won’t need term equality, but we don’t know that yet
Compile-time type checking • A priori we do not know that lML is phase separable • Constructor equality may well depend on arbitrary axioms on terms • So to say that we have a phase distinction, we say formally that equality judgments are derivable in the absence of all term equality axioms
Theories • Parametrize lML by a theory T=(FT, AT) • FT is a well-formed context • ATis a collection of run-time axiomse1 = e2 : s (where ;Àei:s) • lML[T]`J iff J derivable in theory T
Contexts If F is a context • let Fc be F with all term variable declarations removed (compile-time context) • let Fr be F with all constructor variable declarations removed (run-time context) • lML[T]`ctJ iff J derivable using only rules in T; constructor- and type- equality rules and the formation rules (but not the “run-time” term equality rules) of lML
Compile-time type checking If T is a theory, then • lML[T]`Fcontextimplies lML[FT,;]`ctFccontext andlML[FT,;]`ctFrcontext • lML[T]` FÀ u:k implies lML[FT,;]`ctFcÀ u:k • lML[T]` FÀu1=u2:k implieslML[FT,;]`ctFcÀu1=u2:k
Compile-time typechecking (cont’d) • lML[T]` FÀs type implieslML[FT,;]`ctFcÀstype • lML[T]` FÀs1=s2 type implieslML[FT,;]`ctFcÀs1=s2type • lML[T]` FÀe: s implieslML[FT,;]`ctFc,FrÀ e:s • FÀe1=e2:s implies lML[FT,;]`ctFc,FrÀei:s
Compile-time type checking • Note that in the last implication, we only get to conclude lML[FT,;]`ctFc,FrÀei:s • Confirms our intuition that in general term equality is not available to us at compile-time • Compile-time type checking is decidable and independent of all equalities on terms
Modules • Extend lML to a calculus with modules • Based on the dependent type interpretation of sharing as in prior papers we’ve looked at • But non-standard interpretation of what it means to be a dependent product/sum
Structures only k2kind ::= L u2constr ::= L | sc s2type ::= L e2term ::= L | sr S2sig ::= [v:k, s] M2mod ::= [u, e] F2context ::= L | F, s:S
Structures only (cont’d) • Only have structure variable in contexts • New constructor and term rules • Projection rules for open-scope existentials
Structures only (cont’d) Four new judgment forms • FÀS sig • FÀM:S • FÀS1=S2 sig • FÀ M1=M2:S Defined in the expected way (for open-scope existentials)
Compile-time typechecking for structures calculus Show decidable by giving a translation into lML Split contexts F into F¤ by replacing structure variables s:[v:k,s] with sc:k, sr:[sc/v]s
Compile-time typechecking for structures calculus (cont’d) For any lML theory T, • lMLstr[T]`FÀ[v:k,s] sigiff lML[T]`F¤,v:kÀstype • lMLstr[T]`FÀ [u,e] mod iff lML[T]`F¤Àu:kand lML[T]`F¤Àe:[u/v]s • Similarly for equality judgments
Towards a full module calculus • So what about substructures and functors? • Turns out that they are definable in lMLstr • The remainder of the talk will show how
Intuition • Consider all modules and all operations on modules as being composed of two separate parts: the constructor part and the term part • Example from SML: Given functor F (sig type t val x:t end) : sig type t val x:t end = …we “know” that the result type t does notreally depend on the value x in the argument.
Example (cont’d) • So model F as a structure of a constructor function and a value function with signature: [f:T! T, 8sc:T.set(sc!fsc)]
The full module calculus k2kind ::= L u2constr ::= L | Fst(M) s2type ::= L e2term ::= L | Snd(M) S2sig ::= [v:k,s] | 1 | (Ss:S1.S2) | (Ps:S1.S2) M2mod ::= s | [u,e] | ¤ | hM1,M2i | pi(M) | (ls:S.M) | M1M2 F2context ::= L | s:S
Formation rules • Formation rules are standard for dependent types • Selfification rule for full modules • Necessary since modules may have multiple types
Selfification example structure X = struct type t = int val x : int = 3 end X : sig type t val x : int end X : sig type t val x : int end and
Equational rules (signatures) • Flatten higher-order module signatures to structures • of higher kind: • Pairs for substructures • Functions for functors
Substructures sig structure X : sig type t1 val x1 : t1 end type t2 val x2 : X.t1 * t2 end sig constr t : T £ T val x : p1 t £ (p1 t £p2 t) end ) • Pseudo-SML with a constr declaration for constructors of higher kind
Functors funsig (X: sig type t1 val x1 : t1) : sig type t2 val x2 : X.t1 * t2 end sig constr t : T ! T val x : 8 t1 : T . (t1! t1£ t t1) end )
Strategy for compile-time type checking • Show that lMLmod is a conservative definitional extension of lMLstr • In that the non-standard equational rules for modules are “explained” by a translation from lMLmod into lMLstr. • Neither do they let you prove anything new about structures • Type check by translating down to lMLstr, which we know to be decidable
Translating down • Let -b be the mapping that translates away the higher order modules • Recursively flatten all higher-order modules: Mb = [u,e] even if M is is a dependent sum or product
Translating down (cont’d) • Fst(M)b = u if Mb = [u,e] • Snd(M)b = e if Mb = [u,e] • sb = [sc, sr] • [v:k,s]b = [v:k, [v/v]sb] Where v is a variable that does not occur in lMLmod expressions
Translating down(signatures) • (Ss:S1.S2)b = [v:k1£k2, ([p1v/v]s1£[p1v, p2v / sc, v]s2)] if SbI = [v:ki, si] • (Ps:S1.S2)b = [v:k1!k2,8sc:k1.[sc/v]s1! [vsc/v]s2)] if SbI = [v:ki,si] Left to right direction of the signature equality judgment for lMLmod
Definitional extension • In the sense that If lMLmod`FÀ M:S then lMLmod`FÀ M = (Mb)e : S • Where -e embeds the lMLstr in the module language • Flattened modules are “the same as” higher-order modules
Conservative extension • In the sense that lMLstr`J iff lMLmod`Je • No new equalities possible because of higher-order modules
What does it mean to typecheck lMLmod at compile time? • Disallow b and h for term equivalence • Disallow b and h rules for dependent sums and products • Rules for simple structures [u,e] still allowed,e.g.:
lMLmod[T]`ct • Theorem: If T is a theory, then • if lMLmod[T]`FÀS1 = S2 sigthen lMLmod[FT,;]`ctFÀS1 = S2 sig • This is the clause we care about, since typechecking modules depends on signature equality • if lMLmod[T]`FÀe1=e2:s then lMLmod[FT,;]`ctFÀei:s • if lMLmod[T]`FÀM1=M2: Sthen lMLmod[FT,;]`ctFÀMi:Sand lMLmod[FT,;]`ctFÀ [Fst(M1),Snd(M1)] = [Fst(M2),Snd(M1)]:S • N.B. we don’t have equality of modules at compile time, only equality of their type components • (and other clauses)
Typechecking algorithm • Given by inference rules FÀs³FbÀsbtype FÀS³FbÀSbsig FÀM³FbÀMb : [:k,s] (and similarly for expressions and kinds) • More than just the -b interpretation: produces typing derivations. • For modules M produces the “most specific” (non-dependent) signature
Soundness • If TC[T]`FÀ M ³FbÀ [u,e]: [:k,s] then lMLmod`ctFÀ M: [:k,se] • Similarly for other formation judgments
Completeness • For modules, algorithm produces non-dependent signature: If lMLmod[T]`ctFÀ M:S then TC[T]`FÀ S ³FbÀ [v:k,s] sigFÀ M ³FbÀ [u,e]: [:k,s’]FbÀs’ = [u/v]s type For other compile time formation judgments, algorithm produces the correct type or kind
Conclusion • Phase distinction is essential for practical typechecking of higher-order modules • By interpreting modules as pairs of compile-time and runtime objects, can achieve phase distinction even for functors and substructures • Critically depend on a “rich enough” constructor calculus • Turns out that in such a calculus, higher order modules arise “for free” as a definitional extension