<<

What is a Recursive Module?*

Karl Gary Robert Harper Sidd Puri Carnegie Mellon University Carnegie Mellon University Microsoft Corporation

Abstract also support parameterized, or generic, modules to bet- ter support code reuse. A hierarchical module system is an effective tool for There is no question that hierarchical design is an structuring large programs. Strictly hierarchical mod- important tool for structuring large systems. It has of- ule systems impose an acyclic ordering on import depen- ten been noted, however, that strict adherence to a hi- dencies among program units. This can impede modu- erarchical architecture can preclude the decomposition lar programming by forcing mutually-dependent compo- of a system into “mind-sized” components. In some nents to be consolidated into a single module. Recently situations the natural decomposition of a system into there have been several proposals for module systems modules introduces cyclic dependencies, which cannot that admit cyclic dependencies, but it is not clear how be expressed in a purely hierarchical formalism. The these proposals relate to one another, nor how one might only solution is to consolidate mutually-dependent frag- integrate them into an expressive module system such ments into a single module, which partially undermines as that of ML. the very idea of modular organization. To address this question we provide a type-theoretic In response several authors have proposed linguis- analysis of the notion of a recursive module in the con- tic mechanisms to support non-hierarchical modular text of a “phase-distinction” formalism for higher-order decomposition. Recent examples include: Sirer, et module systems. We extend this calculus with a recur- al.‘s extension of -3 with a “cross-linking” sive module mechanism and a new form of signature, mechanism [21]; Flatt and Felleisen’s extension of called a recursively dependent signature, to support the their MzScheme language with cyclically-dependent definition of recursive modules. These extensions are “units” [8]; Duggan and Sourelis’s “mixin modules” that justified by an in terms of more primitive extend the Standard ML module system with a special language constructs. This interpretation may also serve “mixlink” construct for integrating mutually-dependent as a guide for implementation. structures [6, 71; and Ancona and Zucca’s algebraic for- malism for mixin modules [2]. Each of these proposals 1 Introduction seeks to address the problem of cyclic dependencies in a module system, but each does so in a slightly. different Hierarchical decomposition is a fundamental design way. For example, Flatt and Felleisen’s formalism does principle for controlling the complexity of large pro- not address the critical issue of controlling propagation grams. According to this principle a software sys- of type information across module boundaries. Duggan tem is to be decomposed into a collection of modules and Sourelis’s framework relies on a syntactic transfor- whose dependency relationships form a directed, acyclic mation that, in effect, coalesces the code of mutually- graph. Most modern programming languages include dependent modules into a single module. It is not clear module systems that support hierarchical decomposi- what are the fundamental ideas, nor is it clear how to tion. Many, such as Standard ML [16] and O’Caml[14], integrate the various aspects of these proposals into a full-featured module system. ‘This research was sponsored by the Advanced Research It is natural to ask: what is a recursive module? We Projects Agency CSTO under the title “The Fox Project: Ad- vanced Languages for Systems Software”, ARPA Order No. propose to address this question in the framework of C533, issued by ESC/ENS under Contract No. F19628-95-C- , which has proved to be a powerful tool for 0050. The views and conclusions contained in this document are both the design and implementation of module systems. those of the authors and should not be interpreted as represent- We conduct our analysis in the context of the “phase ing official policies, either expressed or implied, of the Defense Advanced Research Projects Agency or the U.S. Government. distinction” module formalism introduced by Harper, Mitchell, and Moggi [ll] (hereafter, HMM), augmented Permission to make digital or hard copies of all or part of this work for to support recursive types and functions, and to support personal or classroom uss is granted without fee provided that type definitions in signatures [9, 131. The phase distinc- copies are not made or distributed for profit or commercial advan- tion tage and that copies bear this notice and the full citation On the first Page. calculus provides a rigorous account of higher-order To copy otherwise, to republish, to post on servers or to modules (supporting hierarchy and parameterization) in redistribute to lists, requires prior specific permission and/or a fee. a framework that makes explicit the critical distinction SIGPLAN ‘99 (PLDI) 5/99 Atlanta, GA., USA between the static, or compile-time, part of a module 0 1999 ACM l-581 13-033.3/99/001 l-85.00

50 and the dynamic, or run-time, part. This calculus has structure calculus, extending the core language with proved to be of fundamental importance to the imple- a primitive module construct without explicit mecha- mentation of higher-order modules, as evidenced by its nisms for hierarchy (e.g., substructures) or parameter- use in Shao’s FLINT formalism used in the SML/NJ ization (e.g., functors). Primitive modules consist of a compiler [18, 201 and in the TIL/ML compiler [23]. static, or compile-time, part containing the type con- Our analysis proceeds in two stages. First we con- structors of the module, together with a dynamic, or sider a straightforward extension of the phase distinc- run-time, part containing the executable code of the tion calculus with a notion of recursive (self-referential) module. This separation is known as the phase distinc- module. An interpretation of this new construct is pro- tion. An important property of the formalism is that vided by an interpretation of it into the primitive mod- the phase distinction is maintained, even in the pres- ule formalism of the phase distinction calculus. This ence of higher-order (and, as we shall see, recursive) interpretation renders the compile-time part as a recur- module constructs. sive type and the run-time part as a recursive , The main result of HMM is that higher-order mod- as might be expected. In essence a recursive module is ule constructs are a definitional extension of the prim- just a convenient way of introducing recursive types and itive structure calculus. In other words higher-order functions. constructs are already present in the primitive struc- Unfortunately this simple-minded extension does ture calculus in the sense that they may be defined in not go far enough to be of much practical use. As Dug- terms of existing constructs. (This interpretation may gan and Sourelis have observed [7], it is of critical impor- be thought of as a compilation strategy for higher-order tance for most practical examples that the type equa- modules, and indeed this fact has been exploited in the tions that hold of a recursive module be propagated into FLINT [20] and TIL [23] compilers.) This means that the definition of the recursive module itself. In essence we need not explicitly discuss higher-order module con- the definitions of the type components of a recursive structs in this paper, but rather appeal to HMM for a module must be taken to be the types that they will detailed discussion of their implicit presence. eventually turn out to be once the recursive declara- To support the extension with recursive modules we tion has been processed. Accounting for this “forward enrich the core phase distinction calculus with these ad- ” is the core contribution of our work. We in- ditional constructs: troduce a new form of signature (interface) for recursive modules, called a recursively dependent signature, that Singleton and dependent kinds to allow expression allows us to capture the required type identities during of type sharing information in signatures. Related type checking of a recursive module binding. This sig- formalisms for expressing type sharing informa- nificantly increases the expressive power of the recursive tion are given by Harper and Lillibridge [9] and module formalism, and is, we assert, of fundamental im- Leroy [13]. portance to the very idea of recursive modules. A fixed point operation for building collections In this paper we aim to focus on the core issues lying of mutually-recursive type constructors. These at the center of a recursive module system, so we study recursive constructors are definitionally equal to recursive modules in the framework of a small internal their unrollings. We term such constructors equi- language that is sufficient to bring out the main issues recursive, to distinguish them from the more con- and that could be used by a type-directed compiler to ventional iso-recursive constructors, for which con- implement recursive modules. Therefore, we make no versions between the constructors and their un- specific proposals as to what form an external language rollings must be mediated by the explicit use of supporting recursive modules should take, although we an isomorphism. We discuss the interplay of equi- do present most of our examples in a hypothetical ex- and iso-recursive constructors in Section 5.3. ternal language. Indeed, some important questions re- garding the design of an external language remain open, A fixed point operation for building collections of such as the practicality of typechecking. In Section 5 we mutually-recursive functions. As will become ap- make some observations and preliminary proposals re- parent later on, we cannot (as in SML) limit this garding the design of an external language. operation to collections of explicit lambda abstrac- tions. Instead we formalize a notion of valuabil- 2 Type-Theoretic Framework ity (indicating terminating expressions) and a cor- responding notion of total function, essentially as We begin by presenting the framework in which we con- in Harper and Stone [12], but with the additional duct our analysis. We will conduct our examples us- idea that recursively defined variables are not con- ing an informal external language closely modeled af- sidered valuable within the body of their defini- ter the of Standard ML. The external language tions, but are considered valuable in their subse- is then elaborated into the type-theoretic internal lan- quent scope. guage that we describe below. We will treat the elab- oration process informally, illustrating it by examples. In subsequent sections of this paper, we will further aug- Details of how elaboration may be formalized in a gen- ment our structure calculus with various constructs for eral setting appear in Harper and Stone [12]. recursive modules, and then show how those constructs Our internal language is an extension of the phase can be reduced to the elementary constructs discussed distinction calculus of Harper, Mitchell, and Moggi [ll]. in this section. The language consists of two main components: a core calculus, a predicative variant of Girard’s F,, and a

51 The type constructors are largely standard. The kinds K ..- T 1 1 1s(c) 1lk/cl.n;2 1CCY:Q.K~ trivial type 1 contains the trivial term *. The types constructors c ::= a 1 * 1 kmc.c 1 ClC2 I (Cl, c2) I cl + c2 and cl J c2 are the types of total and partial Ti(C) 1 1 I Cl A C2 1 Cl X C2 1 /J(YX.C functions from cl to c2 and are discussed in more detail types u ..- c 1 61 + 62 1 u1 A a2 / Ul x 62 I below. The equi-recursive constructor /.~~:r;.c[a] is is a vcr:n.u fixed point of the equation (Y = c[cy]. Thus /.KZ:K.C[CU]is terms e ..- x I * I Xx:u.e I ele2 I (el, e2) I equal to its unrolling c[~cKK.c[~]]. This is in contrast to Xi(e) 1hcr:n.e 1e[c] 1fix(x:u.e) the somewhat more conventional iso-recursive formula- contexts r ..- e 1qcr : n] 1r[x : u] 1 tion, where conversions between the two must be me- rb t 4 i r[x t 4 diated by explicit operations. In Section 5.3 we discuss how to simplify the type theory to use only iso-recursive constructors. Figure 1: The Core Calculus The final construct, fix(x:u.e) at the term level, al- lows the definition of recursive values. However, we wish to prevent the definition of cyclic data structures such s(c : T) gf S(c) as fix(z : int list. 1: :z), which cannot be defined in qc : IIcml .tc2) Sf l-Iwcl.5(Ccr : fez) ML. We do this by imposing a value restriction on (for Q not free in c) the bodies of recursive definitions. The calculus con- tains judgements I’ I- e J- u asserting that e has type u F 5(*1(c) : /cl) x 5(7rz(c) : 62) S(c : Kl x K2) and terminates without computational effects. (In the S(c : 1) Zf 1 present setting, the only computational effect is nonter- n mination.) With this so-called value restriction in place, the formation rule for recursive values is: Figure 2: Higher-Order Singletons r[x t U] I- e 4 u r I- u type (x G Dam(r)) r I- fix(x:u.e) : u 2.1 The Core Calculus This rule is read: fix(x:u.e) has type u if e terminates The core phase distinction calculus contains four syn- with type u under the assumption that I has type u but tactic classes: kinds, type constructors (or just “con- cannot be taken as valuable. This rules out the cyclic list structors”), types, and terms. As usual, types classify proposed above, since 1: : z is not valuable unless x is terms and kinds classify constructors. The constructors valuable. The value restriction implies that all appear- provide a lambda calculus for constructing types. The ances of x must be guarded by (i.e., within the body of) syntax of the core calculus appears in Figure 1. We a lambda abstraction; lambda abstractions are always shall consider expressioti that differ only in the names valuable, regardless of the valuability status of their free of bound variables to be identical, and write capture- variables. As in Harper and Stone [12], the collection of avoiding substitution of E for X in E’ as E’[E/X]. valuable expressions is enlarged by including a type for The kinds include the kind T of all monotypes; the total (pure) functions, such as cons (: :). The applica- trivial kind 1, containing only the constructor *; de- tion of a valuable total function to a valuable pendent products lk~l .K, containing constructor func- is considered valuable. Total functions are considered to tions from ~1 to ~2 where (Y stands for the argument and be types, but not type constructors, in order to prevent may appear free in ~2; and dependent sums CCK:K~.Q, their erroneous use in conjunction with recursive types. containing constructor pairs built from ~1 and ~2 (re- A similar restriction is made on the formation of spectively) where cy stands for the left-hand member and equi-recursive type constructors. In order to show that may appear free in ~2. As usual, if cr does not appear ~CY:V;.Cis well-formed, one must show that c is contrac- free in ~2, we write ~1 + ~2 for &:~1.~2 and ~1 x ~2 tiue in (Y [l]. This is in contrast to iso-recursive types, for Ca:~l .KZ. which require no such condition. InforpEblly, contrac- Finally, for any constructor c having kind T, the sin- tiveness means that the infinite tree specified by iterat- gleton kind 5(c) contains monotypes definitionally equal ing the body c is actually infinite, or, even more infor- to c. Thus, if c has kind S(c’), the calculus permits mally, that iterating the body “goes somewhere.” Thus, the deduction of the equation c = c’ : T. Singleton pa:T.int x (Y is legal, but ,LKY:T.CYis not. Contractive- kinds provide a mechanism for expressing type sharing ness is formalized in the type theory by a judgement information [9, 131. ‘Although singleton kinds exist only [CYt K] t- c J- K, which is read: c is contractive in kind for monotypes, they may be used in conjunction with n under the assumption that (Y has kind K but cannot dependent kinds to express higher-order sharing infor- be taken as contractiue. The rules for contractiveness of mation. For instance, if c has kind lkT.S(list(cr)), it constructors are similar to those for valuability of terms; follows that c = list : T + T. The definition in Figure they ensure that all occurrences of the recursive variable 2 generalizes this idea.’ are guarded by a type construction operation (such as int x (Y in the above example). ‘Note that higher-order singletons are not defined for kinds containing strictly positive singleton or dependent sum kinds; this would eliminate the useful property that n is a kind when- 2.2 The Structure Calculus ever 5(c : K) is. This does not reduce the expressive power of the construct; any constructor whose kind contains strictly positive Atop the core calculus we erect a structure calculus, singletons or dependent sums can be given a kind (exactly as exactly as in HMM. To review, we add two syntactic coarse) without them. classes, one for flat signatures and one for flat structures

52 constructors C ..- . . . 1 Fsts r I- K kind qCY:n]l- u type terms ..- r[atK] t- ~4% r-La: K][Zt U] I- e .Ju signatures ; ;I= 2 : 7Zds r I- fix(s:[cwc.u].[c[Fsts/~], e[Fst s, Snds/cr, xl]) = modules M ::= [c,e] [a = /.4cm.c,fix(x:u.e)] : [LYXU] contexts r ..- . * * 1r[s : q 1r[S t S] (a, 2, s s! DON?)

Figure 3: The Structure Calculus Figure 4: Phase-Splitting Recursive Modules

(Figure 3). Structures are pairs [c, e] of constructors and resulting in the following typing rule: terms. The left-hand component is referred to as the compile-time (or, static) component, and the right-hand component is referred to as the run-time (or, dynamic) r’s t ~~fi~sf~Mf:~ sig (S fZ Dam(P)) component. Signatures, which classify structures, have the form [(Yx, 01, where LY stands for the compile-time Thus, a recursive module is valid if its body (M) is component and may appear free in 6. The structure, valuable without assuming the recursive variable (s) to [c, e] has kind [OI:IE,u] if c has kind IC and e has type be valuable. If a module M is [c, e], then M will be u[c/o]. Often we will write [o = c,e] as shorthand for valuable exactly when e is valuable (i.e., constructors [c, e[c/o]]. We also add constructor and term constructs are always valuable). Fst s and Snd s for extracting the first and second com- Following HMM, we wish to reduce recursive mod- ponents out of structures named by variables. We will ules to the primitive structure formalism by defin- occasionally treat these constructs as variables and al- ing fix(s:S.M) in terms of primitive constructs. We low substitution for them. will do this by phase-splitting recursive modules The structure calculus shows an explicit phase dis- into run-time and compile-time components. SW- tinction between compile-time and run-time expres- pose S is the signature [cr:~.u] and M is the struc- sions [ll, 41. Static expressions may be separated from ture [c( Fst s), e( Fst s, Snd s)]. Then we can interpret dynamic ones, and static ones will never depend on dy- fix(s:S.M) by wrapping the static and dynamic compo- namic ones. This ensures that programs may be type- nents in fixed point expressions: checked without the need to execute any run-time code. HMM show that higher-order modules can be re- fix(s:S.M) = [a = ~cwc.c(cv),fix(x : u.e(cy,x))] duced to the simple structure calculus given here. Therefore we will omit explicit discussion of higher- This definition is formalized in the type theory by the order modules, without any loss of generality. In this equational rule in Figure 4. This rule parallels the non- paper, we show how recursive modules may similarly standard equational rules from HMM, and illustrates be reduced to the structure calculus given here. In so that recursive modules are already present in the un- doing, we will show that despite the apparent intertwin- derlying calculus. In particular, the formation rule for ing of static and dynamic expressions in recursive mod- recursive modules given above follows from the defini- ules, that the phase distinction can be preserved, just tion and need not appear as a primitive rule. as HMM showed for higher-order modules. 3.1 Trouble with Opacity 3 Opaque Recursive Modules The opaque interpretation of recursive modules is pleas- We begin our examination by considering what we call antly simple, but unfortunately, it is not sufficiently “opaque” recursive modules. These will prove to insuf- expressive to support some desired programming id- ficiently expressive for most applications, but they will ioms. One common application of recursive modules serve to illustrate the main ideas and motivate the more is to break up mutually recursive data types. As a par- complex machinery in the next section. ticularly simple (though somewhat contrived) example, In the (informal) external language, we write an consider an implementation of integer lists as a recursive opaque recursive module definition as: module that defers recursively to itself for an implemen- tation of the tail: structure ret S :> SIG = struct . . . end signature LIST = The structure variable S is, of course, permitted to ap- sig pear free within the structure’s body. The signature SIG type t then expresses all the information that is known about S val nil : t in the body or in the subsequent code. (We borrow the val null : t -> boo1 “: >” from Standard ML 1997 [16] to suggest this val cons : int * t -> t opacity.) In particular, the opaque signature obscures val uncons : t -> int * t the-fact that the types in S are recursively defined. end This declaration construct corresponds to a module fixed point operation in the internal language, written structure ret List :> LIST = fix(s:S.M). For reasons similar to those in the previ- struct ous section, we must impose a value restriction on M, datatype t = NIL 1 CONS of int * Li8t.t

53 val nil = NIL fun make-let (d : dec, e : exp) = LET (d, e) fun null NIL = true I null (CONS -) = false fun make-let-val (id : identifier, el : exp, e2 : exp) = fun cons (n : int, 1 : t) = let val d = Decl.make-val (id, el) case 1 of (* type error! el : exp # Decl.exp *) NIL => CONS (n, List.nil) in I CONS (n’ : int, 1’ : List.t) => LET (d, e2) CONS (n, List.cons (n’, 1’)) end

fun uncons NIL = raise Fail I uncons (CONS (n : int, 1 : List.t)) = end if List.null 1 then and Decl :> DECL = (n, NIL) struct else datatype dec = (n, CONS (List.uncons 1)) VAL of identifier * Expr . exp 1 . . . end type exp = Expr.exp This implementation typechecks properly, and it is observationally equivalent to a conventional implemen- end tation. However, intensionally it is very different, be- cause each use of cons and uncons must traverse the Unfortunately, this code does not typecheck. The call entire list, leading to poor behavior in practice. A more to make-val within makelet-val expects an argument direct implementation is impossible because the opacity with type Decl.exp, which, because of the opacity of of List. t precludes any knowledge that List. t is the Decl, is not known to be the same type as exp, the same as t. type of its actual argument el. The type error occurs Some other examples cannot be written in the because the type system cannot tell that exp is equal to opaque case at all (but see Section 4.3). For exam- Decl . exp, even though an examination of the recursive ple, consider an implementation of abstract syntax trees definition reveals that it is actually true. using mutually dependent modules for expressions and declarations. These modules interact with each other 4 Transparent Recursive Modules through the let expression, which contains a declara- tion, and the val declaration, which contains an expres- The difficulties described in the previous section can be sion. To optimize a common case, the expression code traced to the inability to track sufficient type informa- includes a function for let val expressions that defers tion in the context of a recursive structure binding. In to the declaration code to build a declaration: the abstract syntax example the proposed binding fails to typecheck because within the definition of Expr it is signature EXPR = not apparent that the type exp is equivalent to the type sig Decl.exp, even though this equation will be valid once type exp the recursive binding is in force. Similarly, within the type dec definition of Decl it is not apparent that the type dec val make-let : dec * exp -> exp is equivalent to the type Expr . dec, which will turn out (* let DEC in EXP end *) to be true once the binding is in force. Were this equa- val make-let-val : tion available while the definitions of Expr and Decl are identifier * exp * exp -> exp being typechecked, the entire declaration would be seen (* let val ID = EXP in EXP end *) to be valid, and these very equations would hold true . . afterwards. Similarly, the inefficiency of the suggested end implementation of lists may be traced to the failure to identify the types List. t and t inside the definition of signature DECL = List. sig What is needed is a means of propagating the type type dec equations that will turn out to be true of the recur- sively defined structures into the scope of the recursive type exp val make-val : identifier * exp -> dec definition itself. This makes it possible to exploit the (* val ID = EXP *) recursive definitions of the types involved during type- . checking of the dynamic part of the recursively defined . modules, leading to a much more flexible and useful no- end tion of recursive module. In effect we are exploiting the phase distinction by solving the static equa- structure ret Expr :> EXPR = tions prior to checking the dynamic typing conditions struct of the module. datatype exp = LET of Decl.dec * exp 1 . . How is this additional type sharing information to type dec = Decl.dec be propagated? The obvious solution is to add the ap- propriate equations to the signatures of the modules in- The abstract syntax example may be handled sim- volved. For example, in the list example we may prop- ilarly to the list example, as shown below. The recur- agate the required information as follows: sively dependent signatures ascribed to Expr and Decl structure ret List :> allow Decl .make-val’s second argument to be given the sie type Expr.exp, and under the transparent interpreta- tion of datatypes, exp = Expr. exp holds within the datatype t = NIL 1 CONS of int * m] scope of exp. Consequently, the call to Decl.make-val is type correct. val cons : int * t -> t structure ret Expr :> val uncons : t -> int * t sig end = . . . datatype exp = The boxed phrase highlights the occurrence of the struc- ture variable introduced by the recursive structure bind- vaZS:-~[ I & -> exp ing. Since the signatures of the recursively defined val make-let-val : structure variables depend on the structures themselves, identifier * exp * exp -> exp we call these signatures recursively dependent signa- tures, or rds’s for short. In Section 4.2 we shall see how recursively dependent signatures are formalized. end = The purpose of a recursively dependent signature is struct to express the sorts of recursive type equations that are datatype exp = LET of Decl .dec * exp I . . . required to recover the ill-formed examples of the pre- ceding section. Let us now revisit those examples to see fun make-let (d : Decl.dec, e : exp) = how rds’s are used to resolve the difficulties those ex- LET (d, e) amples raise. Using a recursively dependent signature it is possible to give an implementation of lists with fun make-let-val (id, el : exp, e2 : exp) = constant-time primitive operations as follows: let val d = Decl.VAL (id, el) structure ret List :> (* typechecks, since exp = Expr.exp *) sig in datatype t = NIL 1 CONS of int * List.t LET (d, e2) end

val cons : int * t -> t end : t -> int * t val uncons end Decl :> end = sig struct iatatype dec = datatype t = NIL 1 CONS of int * List .t VAL of identifier * -1 I . . . val make-val : fun cons (n : int, 1 : t) = CONS (n, 1) identifier * (ExDr.exDI -> dec fun uncons NIL = raise Fail I uncons (CONS (n, 1)) = (n, 1) end end = struct . . . end The effect of the recursively dependent signature in this In each of these examples, the recursively dependent example is to ensure that the implementation type of signatures used were fully transparent, in the sense that the recursive datatype List. t coincides with the imple- every type component was given by an explicit type def- mentation type of the type t within the body of the inition. This was necessary in order to make the given definition. examples typecheck. More generally, fully transparent This example also raises a important point about re- rds’s provide optimal propagation of type information, cursive datatypes in the context of a recursive structure thereby maximizing the of programs that can be binding. We must impose a structural, or transparent, typechecked. Moreover, we will see in Section 4.2 that interpretation of recursive datatypes within the scope in order to phase-split recursively dependent signatures, of a recursive structure binding, rather than the more it is necessary to require full transparency of all rds’s, familiar nominal, or opaque, interpretation used in Stan- and to require a contractiveness condition of them as dard ML. In type-theoretic terms the rds ascribed to well In Section 5.1 we illustrate how the elaborator List is tantamount to a signature that transparently de- can ensure that these conditions are satisfied. fines the type t to be the underlying iso-recursive type of the recursive datatype. We note, however, that this 4.1 Functorr and Separate Compilation interpretation can be limited to the recursive structure binding itself, and need not propagated into the subse- In the preceding abstract syntax example, the mutually quent scope of the binding: the elaborator may “seal” recursive modules Expr and Decl were compiled simul- the structure with an opaque signature hiding the im- taneously in a single recursive definition. In practice, plementation type of List. t after the binding has been however, it is important for it to be possible to compile processed. each mutually recursive module separately [7j. In the

55 absence of separate compilation, the structuring of code 4.2 Formalization of Recursively Dependent Signa- as mutually recursive module definitions would often be tures a largely cosmetic exercise. One may separately compile mutually recursive The addition of recursively dependent signatures to the modules by rewriting them as closed functors and then phase distinction calculus is performed in two stages. gluing those functors together by instantiating them in First, we extend the syntax of signatures with the recur- a recursive structure binding. Each closed functor may sively dependent form, which we write pa.S, and extend then be separately compiled. However, it is instructive the signature formation and equivalence rules with rules to examine the details, as a naive attempt to do so runs governing this new form. We also extend the module afoul of the opacity problem once again. This problem formation rules to include introductory and eliminatory is demonstrated by the following functorized version of rules for recursively dependent signatures. Second, we the abstract syntax example: show that this enrichment of the structure calculus may be interpreted into the original structure calculus (over structure ret Expr :> sig . . . end = the extended core language described in Section 2) by ExprFun (Expr, Decl) exhibiting an equation between rds’s and ordinary sig- and Decl :> sig . . . end = natures. DeclFun (Expr, Decl) Informally, the recursively dependent signature pa.S contains those modules M that belong to S where s may functor ExprFun (structure Expr : EXPR appear free in S and stands for M. In other words, M structure Decl : DECL) = belongs to pa.S when M belongs to S[M/a]. Formally, . . . as above . . . rds’s adhere to the following introductory and elimina- tory rules: functor DeclFun (structure Expr : EXPR structure Decl : DECL) = r k M : S[M/a] r I- p3.s sig l- I- M : pa.S . . . as above . . . I? i- M : pa.S r‘ I- M : S[M/a] When defined in this manner, ExprFun does not type- As discussed previously, in the rds pa.S we require that check because the Expr and Decl are given the static component of S be fully transparent, that opaque signatures, causing exactly the same problem as is, that it completely specify the identity of its static in Section 3.1. To make this work, we must use recur- component using singleton kinds. Thus, in order for an sively dependent signatures for the functor’s parame- rds pa.S to be well-formed, S must be fully transparent ters: and well-formed under the assumption that a has signa- ture S’, where S’ is obtained from S by stripping out functor ExprFun the singleton kinds specifying the identity of the static (structure ret Expr : component. Formally, rds’s have the following forma- sig tion rule:* datatype exp = LET of Decl.Dec * exp I . . . rt- s sig r+ t s] t- c-1 K qS : q I [Ly:5(c: K),B] sig end r t- ps.[a5(c: K), u] ig (i!::;;:,;;I) and Decl : sig . . . end) = . . . as above . . . The third subgoal is the contractiveness condition al- luded to previously. This may be seen as part of the full This example now reveals an important limitation transparency requirement, since if c is noncontractive in on the degree of separate compilation that is possible. s, then it is just retelling a, and provides no useful infor- This version of the functor typechecks and may be com- mation. Both the full transparency and contractiveness piled independently, but in order to make it typecheck, conditions are necessary in order to interpret rds’s into we have been forced to provide a recursively dependent the basic structure calculus, as we will see in a moment. signature for both Expr and Decl, thereby specifying all As with the recursive modules of Section 3, we wish the type components of the other module Decl. Hence to reduce recursively dependent signatures to primitive we observe that the code may be independently com- constructs of the structure formalism. We do this by piled, but in some sense the types may not, since they wrapping the compile-time component of the rds in a must be kept consistent among both mutually recursive fixed point expression, and by redirecting recursive ref- components. erences in the run-time component: This is not a frivolous restriction; it is a simple con- sequence of supplying enough type information to al- ps.[cu:b(c(Fs’sts) : K), b(ct, Fst a)] low each module to typecheck. However, the restric- tion is stronger than necessary in one regard: we re- [a5(aP:n.c(P)I : K), u(c+J)] quire that rds’s be fully transparent, but it is not al- ways necessary to know the definitions of all the type In the second highlighted fragment, recursive components of a mutually recursive module (though it using Fsts are redirected to use cr. The interesting was in the abstract syntax example). Therefore we may part is the first highlighted fragment: Suppose [c’,e] gain some additional expressiveness by relaxing the full transparency requirement of rds’s. We discuss how to aRecall that we consider Fst 8 to be a variable and allow sub- do this in Section 5.1. stitution for it.

56 r I- K: kind I’[p : K] i- S(C : K) kind l?p t K] !- c 4 rc I$ : rc] I- u[a/Fsts] type r t- ps.[~5(~[ms/p] : K),U] = [ccs(~~x.~: K),+/i+t s]] 3ig h A 8 s;rDam(r))

Figure 5: Phase-Splitting Recursively Dependent Signatures

is a prospective member of the rds on the left. Since can always program opaquely (i.e., without any type Fst [c’, e] (so to speak) is c’, the rds dictates that c’ have sharing information) if one is willing to incur mediat- kind S(c(c’) : IC), and consequently that c’ = c(c’) : IC. ing function calls between types that are actually equal. Therefore, c’ may be taken to be @:~.c(/3), as provided Tools for supplying type equality information, such as by the first highlighted fragment. sharing [15], translucent sums [9,13], and recursively de- This definition makes clear the need for full trans- pendent signatures, serve only to improve performance. parency and contractiveness of rds’s. When translated into the structure calculus, an rds specifies its static 5 External Language Issues component to be @:K.c(~), as above. To extract the necessary constructor c, the rds must be fully transpar- 5.1 Elaboration of Recursively Dependent Signatures ent. Furthermore, c(p) must be contractive in p, or else the specified static component is ill-formed. As discussed previously, the internal language requires The definition is formalized in the type theory by the that all recursively dependent signatures be fully trans- equational rule in Figure 5. As in Section 3, this rule parent and contractive in their static component. In illustrates that recursively dependent signatures are al- an external language, however, this requirement can be ready present in the underlying calculus. In particular, burdensome to satisfy. Therefore, we would like to re- the introductory and eliminatory rules given above fol- move that requirement from the external language, and low from the definition and need not appear as primitive instead have the compiler satisfy the requirement as it rules. elaborate external code into the internal language. In the case of a recursive module definition, it is 4.3 Opacity Revisited easy for the elaborator to supply any omitted type def- initions, because it may inspect the actual module to The phase-splitting rule for recursively dependent sig- discover the omitted information. However, as we saw natures reveals an interesting fact: of the two forms in Section 4.1, it is important to allow rds’s as signa- of recursive dependency, static-on-static (i.e., types on tures for functor arguments. In such cases there is no types) and dynamic-on-static (i.e., terms on types), particular module to inspect for the missing informa- only static-on-static dependencies are essentially recur- tion, so if the elaborator is to rewrite such an rds to be sive (as shown in the first highlighted fragment above). transparent, it must do so without supplying additional In contrast, dynamic-on-static dependencies were re- information. solved without recursion (in the second fragment), sim- Given a prospective rds that fails to be fully trans- ply by redirecting them from the recursive variable parent, the elaborator may transform it to an isomor- (Fst s) to the variable standing for the signature’s static phic signature that is permitted by naming any abstract component (o). Thus, dynamic-on-static dependencies types within the rds and hoisting them out. (A similar are not truly recursive at all. (In fact, such dependencies device is used by the generative stamps in the Definition would never arise when programming in a fully phase- of Standard ML [16].) For example, the signature split style [ll].) Is it possible to program with only dynamic-on- ret S : sig static dependencies and thereby largely dispense with type t recursively dependent signatures? To some degree, type u = s.u -> t yes. (This is the expressiveness provided by Flatt and end Felleisen’s “units” [S].) Recall the abstract syntax ex- can be made permissible by introducing a type defini- ample as corrected using a recursively dependent signa- tion for t setting it equal to an abstract type that is ture. That example used static-on-static dependencies defined outside the rds. The resulting signature is per- in the specifications of exp and dec, and used dynamic- missible because the rds, which now lies within an outer on-static dependencies in the specifications of makelet signature, is fully transparent: and make-val. The dependency of dec on exp was used in makelet-val when constructing a dec (named d) sig from an identifier and an exp. However, the need to type t’ know dec’s specification in terms of exp can be elimi- structure ret S : nated by instead using the function make-val, which is sig specified by a dynamic-on-static dependency. The cost type t = t’ of this is that one must incur a function call whenever type u = S.u -> t going between exp and dec, and such function calls can- end not be safely inlined without using static-on-static de- end pendency information. Recall that we also require that recursively depen- This is an instance of the well-known fact that one dent signatures be contractive. In most cases, the elab-

57 orator can transform signatures to satisfy this require- ment in the same manner as to satisfy transparency. For r t- c = c’[c/a] : K qa j- K] k c’ J. K example, consider the noncontractive signature: r k c = pcr:IE.c’ : K ret S : sig type t = S.t Figure 6: Bisimilarity type u = S.u -> t end Note that the signature does not provide any informa- That S(s) has the form given in the first line follows tion as to the identity of t (except that it is equal to from the well-formedness of ps.S(s); the second line itself). In this case, t is essentially abstract, as it was follows since s’s signature and phase-splitting dictate in the previous example, so the signature can be trans- that Fst s = /@XC(P); the third and fourth lines fol- formed to a permissible one exactly as before. low by equational reasoning using recursive constructors It should be noted that this technique can fail in the and singleton kinds; and the last follows by the phase- presence of unknown type constructors. Suppose f is splitting rule. an unknown constructor with kind T + T and consider the signature: Constructor equality With or without this external- level typechecking strategy, one significant problem for ret S : sig typechecking remains: the typechecker must be able to type t = S.t f determine whether two constructors are equal. This type u = S.u -> t problem is made difficult by singleton kinds and by equi- end recursive constructors. At this time neither problem is In this signature it is not clear whether or not t is ab- known to be decidable, although algorithms exist for stract. If f were the identity, then this signature would singleton kinds that work well in practice. reduce to the previous example, and t could be hoisted. For equi-recursive constructors, Amadio and On the other hand, if f were, say, Xa:T.int + (Y, then Cardelli [l] give an algorithm for checking equality at t would not be abstract and it would incorrect to hoist kind type, but this algorithm does not extend to higher t, and indeed the signature would be properly contrac- kinds. Some recent work suggests that the problem tive. The fact that f is unknown stymies any attempt may be decidable at higher kinds as well: Solomon [22] to resolve this situation. showed in 1978 that type equality with a somewhat similar notion of recursive type could be reduced to equivalence of deterministic pushdown automata, 5.2 Typechecking which was recently shown decidable by SCnizergues [17], An important problem in a practical implementation though not by a very practical algorithm. is typechecking of recursive modules. Suppose a type- These two problems remain the main outstanding is- checker is presented with a recursive module definition: sues confronting a practical implementation of recursive modules. structure ret A : ASIG(A) = struct . . . body . . . end 5.3 Equi- versus Iso-recursive Constructors In terms of the external language, an appealing type- Given the difficulty of typechecking in the presence checking strategy is to check first that the rds ps.ASIG(s) of equi-recursive constructors, a natural question is is well-formed, and second that the body of the struc- whether the reliance on equ&ecursive constructors is es- ture definition has signature ASIG(A) under the assump- sential for supporting recursive modules. (For example, tion that A does. However, it is not immediately clear Duggan and Sourelis’s formalism does not rely on this that this strategy is sound or complete, since the type form of recursive types.) We conjecture that it is not es- theory requires (instead of the second condition above) sential, based on the following observations. Under the that the body have signature ps.ASIG(s) under the as- standard type-theoretic interpretation of ML (for exam- sumption that A does. ple, Harper and Mitchell [lo]), the implementation of a We wish to show that these two typechecking strate- recursive datatype is an iso-recursive type. (We will gies are equivalent. The conditions on the recursive vti- write iso-recursive types as p-c~.c.) If we restrict recur- able A are certainly equivalent, using the introductory sive modules to datatypes (as in Duggan and Sourelis’ and eliminatory rules for rds’s. To show the conditions formalism), and adopt the “transparent” interpretation on the body to be equivalent, we observe that the signa- outlined in Section 4, then equi-recursive types are com- tures ASIG(A) and ps.ASIG(s) are equal whenever A has pletely eliminable by the translation into the underlying signature ps.ASIG(s). structure calculus, provided that we adopt Shao’s equa- Suppose ps.S(s) is a well-formed rds, and suppose tion for iso-recursive types: that the variable s is given that signature. Then (for some c, K and 0): p,a.c(a) = pra.C(p~a.C(a))

S(s) = [cr:5(c(Fst s) : K), a(Fd s)] This equation was introduced by Shao [19] in his FLINT = [a:s(c(&kc(p)) : K), a(pp:r;.c(p))] formalism in order to support the compilation of Stan- = [a:5(/Jp:bLc(p) : K), a(pp:K.c(p))] dard ML. It is also discussed by Crary et al. [5], who = [cr:s(/Jp:K.c(p) : K), u(a)] argue that this equation is already essential for efficient = ps.S(s)

58 Shao’s equation += contractiveness r I- P&.C(p&3) = P4.C(~l,P) r-b t Tl!- cId.C(~,P) -4 (bisimilarity ) r b p&.c(p,P) = pa:T.p,P.c(a,P) : T

Figure 7: Elimination of Equi-Recursive Types compilation of Standard ML’s opaque datatypes, even processed to extract the type information that is to be in the absence of recursive modules. added to the ascribed signature. In the second pass, the The relevance of Shao’s equation to the elimination augmented, fully-transparent signature can be used to of equi-recursive types is based on the following observa- elaborate the run-time parts of the right-hand to com- tion. After translation into the pure structure calculus, plete elaboration. datatypes in the body of a recursive module definition A related question is whether an ascribed signature have implementation types of the form may be omitted entirely in the recursive case. Here we face the difficulty that it is not even apparent what are the type components of the recursively-defined struc- ture, let alone what are their definitions. To recover for some constructor c, where a results from recur- this information would seem to require the kind of sion via recursive modules and p results from ordi- pre-elaboration used in the SML/NJ Compilation Man- nary datatype recursion. By invoking a bisimilarity rule ager [3], whereby the defined components of a module for equi-recursive types (Figure 6) and applying Shao’s are determined before processing begins. equation, as shown in Figure 7, we may prove that this type is equivalent to the type 6 Conclusions

Purely hierarchical module systems, such as the Stan- which is a purely iso-recursive type. dard ML module system, may be criticized on the This observation sheds light on the nature of Duggan grounds that they lack adequate support for cyclic de- and Sourelis’s restriction on the recursively defined type pendencies among components. Several authors (in- components of a mixin module to datatypes, which are cluding Duggan and Sourelis [6, 71 and Flatt and implicitly iso-recursive. Strictly speaking, this restric- Felleisen [S]) have proposed module systems that better tion is not necessary, but if it were to be adopted, it support such cyclic dependencies among units. With would, by the observation above, allow the elimination at least two different proposals for recursive modules in of equi-recursive types from the internal language of a hand, it is natural to ask “what is a recursive module?” type-based compiler for ML. We provide an answer to this question in the form of a type-theoretic analysis of recursive modules based on 5.4 Transparent Signature Ascription the “phase distinction” calculus of higher-order mod- ules [9]. Transparent signature ascription raises significant issues We propose an extension of the phase distinction cal- for the design of an external language with recursive culus with a new form of recursive module and a new modules. In Standard ML it is common practice to form of signature, called a recursively dependent signa- write structure declarations in the form ture. Following the paradigm of the phase distinction interpretation of higher-order modules, we demonstrate structure S : SIG = the sensibility of this extension by giving an interpreta- struct type t=int . . . end tion of it into a pure calculus of structures (without ex- where SIG specifies, but does not define, a type compo- plicit recursive module constructs). This interpretation nent t. The elaborator processes the right-hand side, demonstrates that in a precise sense, recursive modules extracting the binding of t, and implicitly propagating are already present in the pure structure calculus. it to the signature SIG. In effect, the binding is made To make these ideas practical more work remains to opaque, but with an augmented signature containing be done. It is important to demonstrate that typecheck- additional defining equations for types, as follows: ing is decidable in this framework. The central issue is decidability of type equality in the presence of singleton structure S :> SIG where type t=int = kinds and equi-recursive constructors of higher kind. It struct type t=int . . . end is also important to consider a dynamic for It is natural to consider whether transparent ascription the extended language and to demonstrate the sound- may be extended to recursive module bindings. The ness of the type system for this dynamic semantics. difficulty is that the right-hand side of the binding can involve references to S itself. As we have seen, the code Acknowledgements on the right cannot be type-checked in the absence of equations for the type components of the module. One We would like to thank Matthias Felleisen, Matthew approach to this problem is to adopt a two-pass elabo- Flatt, Xavier Leroy, David MacQueen, Zhong Shao, and ration process. In the first pass the right-hand side is the anonymous referees for many helpful comments.

59 References [I71 G6raud SCnizergues. The equivalence problem for deter- ministic pushdown automata is decidable. In Twenty- ill Roberto Amadio and . Subtypingrecursive Fourth International Colloquium on Automata, Lan- types. ACM TOPLAS, 15(4):575+%1, 1993. 9uwe4 and Programming, volume 1256 of Lecture PI Davide Ancona and Elena Zucca. An algebra of mixin Notes in Science, pages 671-681, Bologna, modules. In F. Parisi-Presicce, editor, WADT ‘97 12th Italy, July 1997. Springer-Verlag. Workshop on Algebraic Development Techniques - Se- I181Zhong Shao. An overview of the FLINT/ML compiler. lected Papers, volume 1376 of Lecture Notes in Com- In Proceedings of the 1997 ACM SIGPLAN Workshop puter Science, pages 92-106, Berlin, 1997. Springer Ver- on Types in Compilation, Kyoto, Japan, June 1997. lag. [191Zhong Shao. Equality of recursive types. (Private com- [31 Matthias Blume. Hierarchical Modularity and Inter- munication), September 1998. module Optimization. PhD thesis, Princeton Univer- Zhong Shao. Typed cross-module compilation. In 1998 sity, Department of Computer Science, Princeton, New PO1 Jersey, November 1997. ACM SIGPLAN International Conference on Func- tional PFogramming, pages 141-152, Baltimore, Mary- 141 Luca Cardelli. Phase distinctions in type theory. Un- land, September 1998. published manuscript. WI Emin Giin Sirer, Marc E. Fiucynski, Przemyslaw [51 Karl Crary, Robert Harper, Perry Cheng, Leaf Petersen, Pardyak, and Brian N. Bershad. Safe dynamic link- and Chris Stone. Transparent and opaque interpreta- ing in an extensible . In Workshop tions of datatypes. Technical Report CMU-CS-98-177, on Compiler Support for System Software, Tucson, Ari- Carnegie Mellon University, School of Computer Sci- zona, February 1996. ence, November 1998. WI Marvin Solomon. Type definitions with parameters (ex- k31Dominic Duggan and Constantinos Sourelis. Mixin tended abstract). In Fifth ACM Symposium on Princi- modules. In 1996 ACM SIGPLAN International Con- ples of Programming Languages, pages 3138, Tucson, ference on Functional Programming, pages 262-273, Arizona, January 1978. Philadelphia, Pennsylvania, June 1996. 1231 David Tarditi, Greg Morrisett, Perry Cheng, Chris 171 Dominic Duggan and Constantinos Sourelis. Parameter- Stone, Robert Harper, and Peter Lee. TIL: A type- ized modules, recursive modules, and mixin modules. In directed optimizing compiler for ML. In ACM SIG- 1998 ACM SIGPLAN Workshop on ML, pages 87-96, PLAN Conference on De- Baltimore, Maryland, September 1998. sign and Implementation, pages 181-192, Philadelphia, [81Matthew Flatt and Matthias Felleisen. Units: Cool Pennsylvania, May 1996. modules for HOT languages. In 1998 ACM SIGPLAN Conference on Programming Language Design and Im- A Type Theory plementation, pages 236-248, Montreal, Canada, June 1998. A.1 Core Calculus PI Robert Harper and Mark Lillibridge. A type-theoretic approach to higher-order modules with sharing. In II-l-n kind] Twenty-First ACM Symposium on Principles of Pro- gramming Languages, pages 123-137, Portland, Ore- r t- c : Type gon, January 1994. r I- T kind r I- 1 kind r I- 5(c) kind WJI Robert Harper and John C. Mitchell. On the type structure of Standard ML. ACM Transactions on Programming Languages and Systems, 15(2):211-252, April 1993. Pll Robert Harper, John C. Mitchell, and Eugenio Moggi. Higher-order modules and the phase distinction. In Seventeenth ACM Symposium on Principles of Pro- gramming Languages, San Francisco, California, Jan- uary 1990. 1I- I- nl = n2 kind 1 WI Robert Harper and Chris Stone. A type-theoretic in- terpretation of Standard ML. In Proof, Language and Interaction: Essays in Honour of Robin Milner. The r k T = T kind r’ I- I= 1 kind MIT Press, 1998. To appear. r I- cl = c2 : Type 1131 Xavier Leroy. Manifest types, modules, and separate compilation. In Proceedings of the Twenty-first Annual r k B(Q) = 5(c2) kind ACM Symposium on Principles of Programming Lan- guages, pages 109-122, Portland, Oregon, January 1994. r t- sE1= K{ kind 1141 Xavier Leroy. The Objective Cam1 system: r[a : nl] I- n2 = 6; kind Documentation and user’s guide. Available at (a ~2DON’)) http://pauillac.inria.fr/ocaml/htmlaan/.,1996. r I- lJa:nl .n2 = rI~a:,+$ .K; kind 1151 David MacQueen. Modules for Standard ML. In 1984 ACM Conference on Lisp and Functional Program- r I- IQ = s: kind ming, pages 198-207, Austin, Texas, August 1984. r[o : nl] I- n2 = 6; kind (a e Dam(r)) [161 Robin Milner, Mads Tofte, Robert Harper, and David r k CCX:~~.n2 = &Y:K; .K; kind MacQueen. The Definition of Standard ML (Revised). MIT Press, 1997.

60 I’ I- nl kind I’[, : nl] t- c J. ~2 (a 4 Dam(r)) I? I- T 5 T kind I? I- 1 5 1 kind r I- Xcwc~ .c 1 na:tcl.nz

r I- cl = c2 : Type ri-c:T rtc, ~~~~~~~~~ rkc24nl I? I- S(Q) 5 S(Q) kind I? t 5(c) 5 T kind r t- clc24 fi2hb1

r I- 6; 5 IE~ kind r[a : K;] I- n2 < tc; kind r t- c24. ~2kli4 r[a : tq] I- n2 kind r[a : ~1 I- 62 kind (a ~ Dam(r)) (a 4 Dom(W I? I- IIcz:K~ .KZ 5 IIa:n; .K; kind rt- (ClrC2) ~~wc~.K~

r t- c 1 Ca:nl.Ic2 r i- c~~a:nl.n2 rf-+)hl r t- r2 (4 4 ~~t7bkv4

i=Fcl:T i=bc2:T FFcl:T i=‘t-c2:T

Irt-C:Kl ri-cl~cz$T rl-ClXC2J.T

m t-w rl-a:n (d-7 -rk*:l

r!-ccJ.d rl-fi’

rl-q:T Jl’i-c2:T rl-q:T rl-cz:T rb c2 = c; : nI rl-clAq:T rkcl xcz:T rk c1 = c; : na:nl.n2 r b clcz = c;c; : n2[c2/a]

rI-cl=c; : K.1 r k c2 = C; : Q[c~/~] I?[& : Q] I- ~2 kind r I- c : 6’ r t- 6’ < n kind b e Do4’)) rkczn rf- (cl,c2) = (c;l~;j : ~Y:K~.K~

r t- ~~~~~~~~: na:nl.K2 rkc=c':Ca:61.62 (a not free in c) rk c: rb:~~.~~ r b A1tC) = ~~(2) : nl

r t- (nI(C),ff2(c)) :ccwc~.~~ r k c = d : ~~~~~~~~ rk c: xa:nl.n2 r F T2(c) = ~~(2) : ~c~[v(c)/c~

rtcl=c; :T rI-cz=4:T

iY[a : It] if [B] is [a t 8c] r k c1 2 c2 = c; 2 c; : T F’[Bl otherwise rkclzc: :T rtc2=4:T r f- Cl x c2 = c; x c; : T

61

r I- M: S' r I- S' 5 s sig ~ -- I rtul xu2 = ui x ui type i+ in] t ~4% l?[a t K] t c' 1 n r-t- n = K' qa :t~] I- D = 0' type (a e Dam(r)) (a e Dam(r)) r-t- pa:K.c = p~:~~.c~: K r b v~:K.~ = Va:n’.a’ type jrte:ul r t- c1 = c2 : d I- t tc’ 5 n kind rbccl=c2:6 G (X : 0 E r) rl-l:a w-r) -rt*:i

r k u type rp:u]t eJ-a r k-c :$(c') rkc:i (X !ZDam(r)) rkczc':T rkc=*:i r t Xx:u.e:u --f u' rtg type ql:u]t e:o r k c1 : nl qo: 611tc2 :s2 rt h7.e: D --Ld (x @D-(r)) r k (k~:~l.~~)~l = c~[c~/cY]:K~[cI/~ (a e DOW)) r t el :U+U rte2:u r i- C: na:~l.~2 rl-elez :u’ (a not free in c) rt (x~:K~.~~)= c :rhnl.~2 ri-el:~--Id rl-ee;l:u l?telez :d r I- Cl : ICI r k c2 : K2 (i = 1,2) el 6, e2 ri-e:al xu2 r t .1ri((cl,c2))= c; : fci rt : rt :u2 (i = 1,2) rt(el,ez):cq xu2 r t K;(e): Ui rk C: ~PQ.K~ r I- n kind I’[& : IC] I- e J-U r t- (H1(C),AZ(C))= c: Ccml.IEZ (a fl Dam(r)) r t Aaxe :Va:n.u rtK kind rpt6]tcan r t e:va:n.a r k C: K r t pLa:~.~= c[(p~:~.c)/a] : K (a e Dam(r)) r t e[c] : u[c/a] r FU type r[zfa]te.4g r t c = cq~/a] : n rya tn] t C'J-IC (a ~2Do&T) r t jix(x:u.e) :a r k c= pa:d : n (0 e Dam(r)) rt- e:d rtu = 6' type rt-e:u l?kc:T r b cl type r to2 type r t- c type rt ol 3 u2 type txruer) - rtsJO rt*Ji r t o1 type r b b2 type r k u1 type r +a2 type rt 0 type qz:~]k eJ.u r t cl A 62 type r t u1 x u2 type (X sl DOW)) r t Xx:u.e J. 0 3 u’

r I- K kind r[a : K] I- u type r t 0 type r[33:g]t e :(I (0 St DOG’)) (X t! Do+)) r t Vff:t~ type r t Xx:u.e .I. u 2 u’ r I- u1 = u2 type

r t 0 type rt-a2 = ul type r t u = u type r bual = u2 type ri-e14ul ri-eez402 ytex;pe; ;z (i = 172) r~(el,e2)lalxo2 r t o1 = u2 type r i- u2 = ~3 type r t UI = c3 type r t PCkind r[a : K] I- e 1 u (a sf Dam(r)) I? I- Aaxe .j. VWLU rtc= c': T rteJ.va:n.0 rkc:6 r t c = C' type r I- +I L 444

rtal = 0; type rt02 = u; type rku type qxta]t e&u (X e Do43) r t cl -b u2 = U; + U: type r I- jix(x:u.e) -1 u

rtul = u; type rtu2 = 01 type rt e3.U’ rt 0 = 0' type rt- u1 2 u2 = U: - ui type rtelo

62 A.2 Structure Calculus r k M : s r k s L: s 3ig [IYC:Kl rI-M:S

r k e J.u[c/a] r t s = [cm, u] aig (3 t s E q ricr :K] i- u type l-‘l-Fata:n r i- [c,~]4 [wc,~] (a 61Do43

r I- M&S’ r b S' 5 s aig rl-ML.5

rkM’J.S PI-M=M’:S rkM&S r k s = [CS,U] 3ig (a : s E I-) l- I- Snd s : a[Fat s/a] ri-M:S I-i-M2 =M1:S r f- s = [w,u] 3ig (8 t s E 0 rl-M=M:S ri-Ml =M2:S r I- Snd s : @at a/a] l-‘l-Ml=M2:S I-!-Mz=Ms:S [WJ.al I’!-Ml=Ms:S r k s = [cKK,~]3ig ta: s E r) r I- Snd s 4 a[Fat s/o] rt- c=c':K I? I- e : u[c/cr] ri?Gq q. :n] k 0 type (a 4 Dome’)) r k [c, e] = [c',e] : [a:n,a] r I- n kind r[a : tc] I- Q type (a e Dam(r)) r-i- pzn,O] .9ig l-l-Ml= M2 : S’ r I- S 5 S’ aig rl-Ml=M2:S [FFXZZZl

I-l-s aig r b s2 = s1 3;s A.3 Recursive Module Calculus rcs=s 3ig rbs, =s2 3ig jr!-M:S[ r i- s1 = s, aig r k s2 = s3 3;s r[a t q I- M J. S r k S aig r k s1 = s3 3ig (3 z Dam(r)) ri-fiz(da4): s

r + 6 = IC’ kind r[a : n] k u = u’ type l-l-Ml =M2:S( r i- [w,~] = [cw',u~ 5ig (a G DomU’) I’ !- n kind r[a :ri] i-u type (-1 qat K] I- CJ K qa : K][Ztu] k e 4.0 r I- fir(a:[ol:n.u].\ciFat s/cu],e[Fat S,Snd s/a,z]l) = r i- s1 = s2 aig [a = pa:n.c,fiz(z:u.e)] : [ax, u] r k s1 5 s, aig (a, zc, s tz DomP’))

r t- s1 5 s2 8ig r I- s2 2 s3 aig Iri- S aigl rks,ss, sig r b s 3ig rbtswc~ qs: .q t- [LY~C:~c),u] Jig r I- IG < K’ kind r t- ps.[a:5(~: ~c),u] 3ig qa : K] I- 0 = 0' type ($::;::,",;l ) rp :d]l- 0' type r f- [a:K,u] 5 [cw?,u~ hg (a eDom(r)) I? I- K kind I’[/3 : K] t S(c : K) kind r-10 t 4 t- c J K r[a : K] I- +/Fat S] type r t- ps.[c&(c[Fat s/p] : n), u] = [&(&:n.c : ~),u[a/Fst s]] aig (~4 s B! D-03)

63