
A Type System for Higher-Order Modules Derek Dreyer Karl Crary Robert Harper Carnegie Mellon University Abstract 1.1 Design Issues We present a type theory for higher-order modules that ac- Before describing the main technical features of our lan- counts for many current issues in modular programming lan- guage, it is useful to review some of the central issues in the guages, including translucency, applicativity, generativity, design of module systems for ML. These issues extend to and modules as first-class values. Our theory harmonizes any language of similar expressive power, though some of design elements from various previous work, resulting in a the trade-offs may be different for different languages. simple, economical, and elegant language. This language is useful as a framework for comparing alternative designs, and Controlled Abstraction Modularity is achieved by using is the first language to provide all of these features simul- signatures (interfaces) to mediate access between program taneously and still support a practical type checking algo- components. The role of a signature is to allow the program- rithm. mer to “hide” type information selectively. The mechanism for controlling type propagation is translucency [9, 12], with 1 Introduction transparency and opacity as limiting cases. The design of languages for modular programming is surpris- Phase Separation ML-like module systems enjoy a phase ingly delicate and complex. There is a fundamental tension separation property [10] stating that every module is sepa- between the desire to separate program components into rable into a static part, consisting of type information, and a relatively independent parts and the need to integrate these dynamic part, consisting of executable code. To obtain fully parts to form a coherent whole. To some extent the design expressive higher-order modules and to support abstraction, of modularity mechanisms is independent of the underlying it is essential to build this phase separation principle into the language [15], but to a large extent the two are insepara- definition of type equivalence. ble. For example, languages with polymorphism, generics, or type abstraction require far more complex module mech- Generativity MacQueen coined the term generativity for anisms than those without them. the creation of “new” types corresponding to run-time in- Much work has been devoted to the design of modular stances of an abstraction. For example, we may wish to programming languages. Early work on CLU [17] and the define a functor SymbolTable that, given some parameters, Modula family of languages [33, 2] has been particularly in- creates a new symbol table. It is natural for the symbol ta- fluential. Much effort has gone into the design of modular ble module to export an abstract type of symbols that are programming mechanisms for the ML family of languages, dynamically created by insertion and used for subsequent notably Standard ML [22] and Objective Caml [26]. Nu- retrieval. To preclude using the symbols from one symbol merous extensions and variations of these designs have been table to index another, generativity is essential—each in- considered in the literature [19, 16, 27, 30, 5]. stance of the hash table must yield a “new” symbol type, Despite (or perhaps because of) these substantial efforts, distinct from all others, even when applied twice to the same the field has remained somewhat fragmented, with no clear parameters. unifying theory of modularity having yet emerged. Several competing designs have been proposed, often seemingly at Separate Compilation One goal of module system design odds with one another. These decisions are as often mo- is to support separate compilation [12]. This is achieved by tivated by pragmatic considerations, such as engineering a ensuring that all interactions among modules are mediated useful implementation, as by more fundamental considera- by interfaces that capture all of the information known to tions, such as the semantics of type abstraction. The re- the clients of separately-compiled modules. lationship between these design decisions is not completely clear, nor is there a clear account of the trade-offs between them, or whether they can be coherently combined into a Principal Signatures The principal, or most expressive, sig- single design. nature for a module captures all that is known about that The goal of this paper is to provide a simple, unified module during type checking. It may be used as a proxy formalism for modular programming that consolidates and for that module for purposes of separate compilation. Many elucidates much of the work mentioned above. Building on type checking algorithms, including the one given in this a substantial and growing body of work on type-theoretic paper, compute principal signatures for modules. accounts of language structure, we propose a type theory for higher-order program modules that harmonizes and enriches Modules as First-Class Values Modules in ML are “second- these designs and that would be suitable as a foundation for class” in the sense that they cannot be computed as the the next generation of modular languages. results of ordinary run-time computation. It can be useful to treat a module as a first-class value that can be stored into a data structure, or passed as an ordinary function argument Static and Dynamic Effects The “sealing” [9] of a module or result [9, 23]. with a signature (aka “opaque signature ascription”), which is used to create abstract and/or generative types, is deemed Hidden Types Introducing a local, or “hidden”, abstract by our type system to induce a pro forma computational ef- type within a scope requires that the types of the externally fect. This is backed up by the intuition that generativity visible components avoid mention of the abstract type. This involves the generation of new types at run time. For our avoidance problem is often a stumbling block for module type system, we set the class of determinate modules to be system design, since in most expressive languages there is precisely the pure, effect-free modules. Thus, a module con- no “best” way to avoid a type variable [7, 16]. taining any type abstraction via sealing is rendered indeter- minate, which is essential to achieving a correct semantics of type abstraction. 1.2 A Type System for Modules The framework of effects allows us to distinguish be- The type system proposed here takes into account all of tween, and admit both, generative and non-generative forms these design issues. It consolidates and harmonizes design of type abstraction. In particular, we isolate two distinct elements that were previously seen as disparate into a sin- sorts of computational effects, which we call static and dy- gle framework. For example, rather than regard genera- namic. Static effects model the hiding of type information at tivity of abstract types as an alternative to non-generative compile time (i.e., non-generative type abstraction), while types, we make both mechanisms available in the language. dynamic effects model the generation of new types at run We support both generative and applicative functors, ad- time (i.e., type generativity). Dynamic effects allow us to mit translucent signatures, support separate compilation, encode generativity without resorting to the use of “genera- and are able to accommodate modules as first-class val- tive stamps” [22, 19]. Since sealing is the principal means of ues [23, 28]. creating abstract types, we also provide two forms of seal- Generality is achieved not by a simple accumulation ing corresponding to the two kinds of effects: weak sealing, of features, but rather by isolating a few key mechanisms which induces a static effect, and strong sealing, which in- that, when combined, yield a flexible, expressive, and im- duces both a static and a dynamic effect. plementable type system for modules. Specifically, the fol- lowing mechanisms are crucial. Applicative and Generative Functors An applicative func- tor [13] is one that respects static equivalence of its argu- Singletons Propagation of type sharing is handled by sin- ments. This models the behavior of functors in Objective gleton signatures, a variant of Aspinall’s and Stone and Caml. A generative functor does not respect equivalence— Harper’s singleton kinds [32, 31, 1]. Singletons provide a the abstract types in the result differ on each application. simple, orthogonal treatment of sharing that captures the The applicative/generative dichotomy falls out very cleanly full equational theory of types in a higher-order module sys- from our treatment of abstraction via effects. Specifically, a tem with subtyping. No previous module system has pro- generative functor is one whose body may contain dynamic vided both abstraction and the full equational theory sup- effects, corresponding to generative types, while the body of ported by singletons,1 and consequently none has provided an applicative functor may contain only static effects. optimal propagation of type information. Existential Signatures In a manner similar to Shao [30], Static Module Equivalence The semantics of singleton sig- our type system is carefully crafted to circumvent the avoid- natures is dependent on a (compile-time) notion of equiva- ance problem, so that every module enjoys a principal sig- lence of modules. To ensure that the phase distinction is nature. However, this requires imposing restrictions on the respected, we define module equivalence to mean “equiva- programmer. To lift these restrictions, we propose the use
Details
-
File Typepdf
-
Upload Time-
-
Content LanguagesEnglish
-
Upload UserAnonymous/Not logged-in
-
File Pages15 Page
-
File Size-