480 likes | 624 Views
Translucent Existentials and Sums. Robert Harper Fall Semester, 2002. Transparency and Opacity. Dependent types are transparent . Propagate type sharing by substitution. No support for type abstraction. Existential types are opaque . Representation type is hidden from client.
E N D
Translucent Existentials and Sums Robert Harper Fall Semester, 2002
Transparency and Opacity • Dependent types are transparent. • Propagate type sharing by substitution. • No support for type abstraction. • Existential types are opaque. • Representation type is hidden from client. • No support for transparency.
Transparency and Opacity • Dependent types run afoul of effects. • Replication or deletion of effects. • Effectful expressions in types. • Sensible in a second-class module system. • Existential types are compatible with effects. • But opacity is a high price to pay!
Transparency and Opacity • Existential types support separate compilation. • Interfaces are existentials. • Complete separation of code from types. • Dependent types conflict with separate compilation. • Sharing is propagated by substitution.
Transparency and Opacity • Separate compilation and effects are important. • Suggests using existentials. • Type dependency is important. • Suggests using dependent types. • Controlled sharing propagation is essential. • Suggests something else is needed.
Effects, Revisited • Existentials are maximally pessimistic. • If e : 9 t.t, then no information about the type part of e is available statically. • eg, e = if moon-is-full then e1 else e2. • But this is a “worst-case” scenario! • e = packtwithl x:t.x • e = packtwith (print “hello”; l x:t.x)
Determinacy • A module is determinate iff its type component is well-defined. • First-class: truly indeterminate modules. • Second-class: pro forma indeterminacy, but no per se indeterminacy. • Module values are determinate. • Explicit package of a type with a value. • Variables, paths (assuming CBV).
Full Expressiveness • The type of a module should capture its entire static significance. • Identity of type components. • Type of value components. • Need type definitions in interfaces. • Capture representation type. • Programmer-controlled degree of abstraction.
Translucent Existentials • Enrich existentials with type definitions: • 9 t.t for opaque types; • 9 t=s.t for transparent types. • Packages do not change. • But any equations must be satisfied! • Dot notation: • repn(e) for the representation type of e; • opns(e) for the operations of e.
Translucent Existentials • Propagation of type sharing information: • G`9 t=s.t´9 t=s.{s/t}t • “Forgetful” subtyping: • G`9 t=s.t <: 9 t.t, • if G `t´t’, then G `t<:t’ • Thus, 9 t=s.t <: 9 t.{s/t}t
Dot Notation • If e is determinate of type 9 t=s.t, then repn(e) ´s. • If e is determinate of type 9 t.t, then repn(e) is equal only to itself. • If e is indeterminate, cannot form repn(e). • There is no unique representation type!
Dot Notation and Effects • Typing rules for opns must take account of effects! • First cut: G `D opns(e) : {repn(e)/t}t • But this involves substitution! • Problem: repn(e) is a type involving e. • No better off than with dependent types! • What if e is indeterminate?
Dot Notation and Determinacy • Suppose e : 9 t.t. • If e is determinate, then repn(e) is sensible, hence so is opns(e). • If tdoes not involve t, then opns(e) is sensible. • Substitution is vacuous, so opns(e) : t. • e can be determinate or indeterminate.
Dot Notation and Transparency • Note: the type of opns(e) does not depend on repn(e) if e : 9 t=s.t. • Propagate sharing to eliminate t from t. • Theorem: If e is a value, then it has a non-dependent type! • Explicit packages: propagate sharing. • Variables (and paths): selfification.
Dot Notation and Transparency • WLOG we may admit opns(e) only when e has a non-dependent type. • Always if e is a value (by the theorem). • Always if representation is explicitly exposed (even if e has effects). • Never if e is genuinely indeterminate. • This is the key to dot notation in the presence of effects!
Dot Notation and Transparency • Packages have transparent types: • packswith e : 9 t=s.t, if e : {s/t}t. • Package type can be weakened by subsumption. • packswith e : 9 t.t. • Sealing forces weakening. • (e:9 t.t) : 9 t.t
Selfification • Suppose that G(x) = 9 t.t. • Selfification: G` x : 9 t=repn(x).t. • repn(x) is well-formed because variables are determinate. • propagates an “obvious” fact to the type. • Extends to paths opns(opns(…(x)…)). • Deemed valuable because projection is “total” (does not affect determinacy).
Selfification • Selfification is essential for principal types for modules. • sig type t val x:t end is not principal for x, even though x is declared with this type! • selfification yields the most precise type for x, namely sig type t=x.t val x:t end. • all types for x are supertypes. • singletons reveal the full story (later).
Selfification • Without selfification we cannot form opns(x)! • Typing rule precludes dependency. • Without selficication we incur excessive abstraction. • structure S’ = S yields S’.t different from S.t • Leads to a more elegant type theory. • But incompatible with “by name” binding!
Dependency • Similar ideas apply to dependent types! • Avoid substitution, because of effects. • Substructure selection and functor application are restricted to the non-dependent case. • First, propagate type sharing. • Second, perform elimination operation.
Substructure Selection • Suppose that e : S s:t1.t2. • the natural type for p2(e) is {p1(e)/s}t2 • but what if e has an effect? • How can s occur free in t2 ? • only as repn(p(s)), where p is a path. • if p(s) is transparent, substitute to remove dependency. • if e is a value, all paths from s can be made transparent by path selfification.
Substructure Selection • Can always admit p1(e). • no issue of sharing propagation. • Admit p2(e) iff e : t1£t2. • That is, e : S s:t1.t2 with s not free in t2. • Dependency eliminable iff e is determinate. • Otherwise it makes no sense to form p2(e)!
Functor Application • Suppose that e : P s:t1.t2. • Consider the application e(e1). • Natural type: {e1/s}2. • But what if e has an effect? • Require that s does not occur free in t2. • Can only arise in the form repn(p(s)). • Always possible if e1 is a value!
Functor Application • Subtyping for functor types is • covariant in the range • contravariant in the domain • We can weaken a functor type by strengthening its domain type! • Add more sharing to the domain. • Propagate sharing to eliminate dependency.
Functor Application • Suppose that t1 = 9 t.s1 and that t2 = 9 t=repn(s).s2. • So t = P s:t1.t2 is dependent. • Suppose that e : 9 t.s1 is a value. • So e : 9 t=r.s for some r. • By subsumption F has type P s:t1’.t2, where t1’ = 9 t=r.s1.
Functor Application • By sharing propagation we may eliminate dependencies on s from t2. • Replace repn(s) by r. • Thus F has type P s:t1’.{r/repn(s)}t2. • Write t2 as {repn(s)/t}t2’. • Then form t2’’ = {r/t}t2’. • So F has type t1’!t2’’, hence F(e1) : t2’’. • Regardless of whether e1 has an effect!
Functor Application • Every value must have a “fully transparent” type. • All type paths starting from that value have a definition. • Thus repn(p) may be replaced by its definition.
Harper-Lillibridge • The H-L formalism is based on translucent sums. • Dependent records with type and value components. • Labels (for external access) separated from variables (for internal access). • Subtyping may forget components.
Harper-Lillibridge • Translucent sums: { d1, …, dn } • Each di is a declaration of a type or a value. • Declarations: • Type component: l Ba :: k [=t] • Value component: l B x : t • External vs internal access: • Labels are used for paths (projection). • Variables are used for internal dependencies. • It is essential to distinguish these!
Harper-Lillibridge • Elements of translucent sums are dependent records { b1, …, bn }. • Each bi is a binding. • Bindings have the form: • Type binding: l Ba :: k = t. • Value binding: l B x : t.
Leroy: Manifest Types • Superficial differences from H-L. • More ML-like notation, for example. • A few minor technical deficiencies. • Paths cannot be limited to variables at the head. • Different treatment of variable/label distinction.
Translucent Sums for Modules • Translucent sums solve several problems in one framework: • Effectful languages. • Dependent types for structures and functors. • Selective opacity/transparency.
Translucent Sums for Modules • H-L and Leroy provide only very weak support for higher-order modules. • Fully expressive in the first-class case (without restrictions). • Does no capture phase distinction for the second-class case.
Translucent Sums for Modules • The H-L formalism is undecidable! • Subtyping relation is undecidable by an argument similar to Pierce’s for F-Sub. • Leroy’s may or may not be, it’s not clear. • Both formalisms lack principal types! • Serious obstacle to type checking. • Precludes strong separate compilation (pace Leroy’s motivation).
Translucent Sums for Modules • Let T = 9 t.1 and let U = 9 t=repn(s).1, where s is a free variable. • Note that U <: T. • Let t¤ = packtwith¤ : T. • Consider the type s = (T ! U) £ U, and suppose that we wish to avoid s. • Two incomparable supertypes avoid s: • (T! T) £ T • S f:(T! T).(9 t=repn(f(t¤)).1) foranyt.
Translucent Sums for Modules • For a first-order module system we can get by with H-L or L. • HOM weakness not at issue. • But we must avoid the avoidance problem. • Requires elaboration tricks. • More on this later. • O’Caml doesn’t, so its incomplete.
Summary • Translucent sums enrich existentials: • Controlled abstraction. • Fully expressive types. • Support for “dot notation”. • Translucent sums generalize dependent types. • Leroy establishes a precise connection.