• No results found

Names and Modules

In document MLS module Sealing and Functor Design (Page 177-183)

7.6 Directions for Future Work

7.6.2 Names and Modules

Another key direction for future work is to scale the type system presented in this chapter to the level of modules. In the process of preparing this thesis, I spent some time exploring this direction. I sketched the semantics and meta-theory of a safe recursive module construct, as an extension to the DCH language [12] (discussed in Section 2.3). The extension was rather complex and required global changes to the DCH type system. Some of this complexity appears to be unavoidable, but

I believe that some of it was also due to limitations of the DCH formalism. In this section, I will describe at a high level some of the issues that arise in building a safe recursive module extension to the type system of Chapters 3 and 4, and how we may deal with them. Working out the full details of such an extension remains important and non-trivial future work.

In order to scale the work of this chapter to the level of modules with type components, the first thing we must do is integrate names and supports into the core language of Chapter 3. This requires us to adapt the notion of type equivalence modulo a support to account for type constructors of higher kinds and singleton kinds. I believe this step is relatively straightforward, but it involves a global change to the language, which in turn necessitates a reproof of the entire Stone-Harper meta-theory!

The global change is essentially to add a support [S] to the end of every core-language judgment. The support of a judgment indicates the set of names that the derivation of the judgment can simply ignore. Thus, aside from the typing and type equivalence rules given in this chapter, all other rules will have the same supportS in the premises as in the conclusion. Note that, because of singletons, supports must be added even to the well-formedness judgments for constructors and kinds. For instance, a constructor C has kind

s

(D) if and only if C is equivalent to D at kind T. If the two

types are only equivalent modulo support S, then C will only have kind

s

(D) under support S.

Consequently, since the well-formedness of a singleton kind

s

(C) depends on the well-formedness

of C,

s

(C) will only be well-formed under whatever support C requires to be well-formed.

The next step is to integrate names and supports into the module language. This may be done in an analogous way, adding supports to the end of every module and signature judgment form, with the interpretation that the names in the support may be ignored in the derivation of the judgment. On the surface, this seems straightforward, as the effect of “static purity” or “separability” tracked by the module system is completely orthogonal to the effect of dereferencing a recursive variable.

We must introduce asaferec(X.X :S.M) module construct, as well as aboxT(S) signature for classifying recursive module variables. Functors and functor signatures must be annotated with the support of their bodies. The rules for these constructs will combine their typing rules from Chapter 4 with the rules for their term-level counterparts given in this chapter. For example, a natural typing rule for total functors would be:

Γ,X:S0 `M :PS00 [S ∪ T]

Γ`λTtotX:S0.M :P ΠTtotX:S0.S00 [S]

This is very similar to the typing rule for term-level λ-abstractions (Rule 5 of this chapter). On closer inspection, however, an interesting problem arises with regard to the following ques- tion: what is the static part of a functor or functor signature bearing supportT,i.e.,how should we defineFst(λTtotX:S.M) andFst(ΠTtotX:S1.S2)? Sinceλ’s at the constructor level do not have supports,

the only obvious answer is to ignore the supportT, defining Fst(λT

totX:S.M) as λXc:Fst(S).Fst(M)

and Fst(ΠTtotX:S1.S2) as ΠXc:Fst(S1).Fst(S2).

To illustrate the problem with this answer, consider the functor F = λX

tot :1.[int

X

−→int], which takes unit argument and returns a module with a single type component,int−→X int. By the typing rule for functors given above, F can be assigned the signature S = ΠXtot :1.[[

s

(int−→∅ int)]] under the empty support. The point here is that the body is typechecked under the extended support{X }, and under that support the typeint−→X intcan be given the kind

s

(int−→∅ int). Unfortunately, while F may have signature S under the empty support,Fst(F) =λ :1.int−→X int does not have kind Fst(S) = Π :1.

s

(int−→∅ int) under the empty support. This breaks an

7.6. DIRECTIONS FOR FUTURE WORK 163

The problem is that the functor typing rule allows the well-formedness of the static part of F’s body to depend on support X, whereas the body ofFst(F) may not depend on that support. To address this problem, we must either redefine the Fst function or change the module typing judgment. It is not clear how to redefineFstwithout first changing the core-language type system so thatconstructor-level functions may bear supports. While it is possible such an approach could work, it would require a more significant and less obvious change to the equational theory of types than what I described above.

An easier approach, I believe, is to rethink the module typing judgment Γ`M :κ S [S]. Instead of ignoring the names inS in the whole typing derivation for M, suppose that we only ignore them when typechecking thedynamic part of M and that we typecheck the static part of M under empty support. For instance, the typing rules for atomic type and term modules might differ as follows:

Γ`C : K [∅] Γ`[C] :P [[K]] [S]

Γ`e: C [S] Γ`[e] :P [[C]] [S]

The first rule would prevent the body of the functor F, [int −→X int], from being assigned the signature [[

s

(int−→int)]]. More generally, the Fstfunction would regain the property that, if M

has signature S under supportS, then Fst(M) has kindFst(S) under theempty support.

To validate this re-interpretation of the module typing judgment, we also have to change the subsumption rule:

Γ`M :κ S0 [S] Γ`S0 ≤S [S] Γ`M :κ S [S]

This rule is problematic because, for example, it allows a module of signature [[

s

(C)]] to be coerced

to the signature [[

s

(D)]], where C and D are only equivalent modulo support S. An easy way to

remedy this problem is to add to the subsumption rule an extra premise, Γ`Fst(S0) ≤Fst(S) [∅], requiring that the static part of S0 match the static part of S under the empty support.6

Aside from this issue, I believe the integration of names and supports into my module type system should be fairly straightforward. It should be clear from this discussion, though, that supporting static detection of safe recursion involves a non-trivial, pervasive extension to the in- frastructure and meta-theory of the language. It is not so clear whether the added benefit such an extension offers in terms of recursive module efficiency and reliability is worth the added complexity.

6

In extending DCH, which did not have any notion of aFst function, it was necessary to modify the signature subtyping judgment so that Γ`S1 ≤S2 [S] only ignored the names inS when matching thedynamic parts of S1

Part III

Chapter 8

Evolving the ML Internal Language

Parts I and II of this thesis have been devoted to achieving a clearer understanding of the ML module system and of the problem of extending ML with recursive modules. Based on this understanding, I described in Section 2.2 a proposal for unifying the existing variants of the ML module system, and in Section 5.4 a proposal for extending ML with recursive modules. It is time to make those proposals concrete.

In this and the next chapter, I will use the Harper-Stone interpretation of Standard ML [33] as the framework and starting point for defining a new, evolved dialect of ML. As described in Section 2.2.3, the Harper-Stone framework (hereafter, HS) defines SML by translating (or “elabo- rating”) the programmer-level “external” language (EL) into an “internal” language (IL), which is defined by a type system. Following their approach, I will formalize my internal language in the present chapter and my external language in the next chapter.

My internal language is based very closely on the module type system I developed in Chapters 3 and 4 and extended in Chapter 6, which I will refer to as the “simplified IL.” The differences between the simplified and actual IL’s are mostly superficial. For instance, to facilitate the understanding of my new design by one who is already familiar with HS, I have chosen in most cases to use the HS conventions for naming metavariables rather than my own naming conventions from earlier in the thesis (e.g., I use the metavariablesmod and sig here instead of M and S to stand for modules and signatures).

There are a few non-trivial differences, however, which I discuss in Section 8.1. For those familiar with the details of Harper and Stone’s formalism, I also discuss the ways in which my IL differs from theirs. Sections 8.2, 8.3 and 8.4 present the syntax, static semantics and dynamic semantics of my IL, respectively. As the IL is for the most part very similar to the simplified IL, I do not give an explicit typechecking algorithm or repeat the meta-theoretic development of Chapters 3, 4 and 6. Adapting them to the actual IL is completely straightforward.

8.1

Overview

In document MLS module Sealing and Functor Design (Page 177-183)