Recursive modules for programming
Recently, much work has been devoted to investigating extensions with recursion of the ML module system. Two important issues involved are type checking and initialization. Crary, Harper and Puri [3], Russo [23], and Dreyer [5] have given type theoretic accounts for recursive modules. Boudol [1], Hirschowitz and Leroy [11], and Dreyer [4] have investigated type systems which guarantee well-formedness of recursive modules, ensuring that initialization of recursive modules will not attempt to access not-yetevaluated values.
todo The second half, regarding well-formedness and initialization has not been reviewed
Privacy & Intimacy - double vision?
Important feature: no requirement on annotations
They do support fine grained sealing within recursive sub modules
- todo Question: do the two examples they present can be encoded in ours?
- i think so?
module rec ... and ...vsmodule rec .. : struct M1 M2... end
- i think so?
Formalism
-
Syntax:
struct (Z) D1 . . . Dn endvs. ourrec X: S = M, whereMcan be not just a structure -
To obtain a decidable type system, we impose a first-order structure restriction that requires functors 1) not to take functors as argument, 2) nor to access sub-modules of arguments.
-
We need to check: Trivata is shallow checking
lookup:
The look-up judgment does not hold for arbitrary module paths.
struct (Z)
module M1 = (functor(X : sig type t end3) → struct
module M11 = struct end5 end4)2
module M2 = struct type t = int end6
module M3 = Z.M1(Z.M2)7
end
Cyclic Definitions
Dreyer (Dreyer, 2005a) gave a theoretical account for type abstraction inside recursive modules. In particular, he investigated generative functors in the context of recursive modules, by proposing a “destination passing” interpretation of type generativity. There is a critical difference in design choices between us, with respects to type abstraction inside recursive modules. For instance, consider the two programs:
module M = (struct type t = N.t end : sig type t end)
module N = (struct type t = M.t end : sig type t end)
and
module M = (struct type t = N.t end : sig type t = N.t end)
module N = (struct type t = M.t end : sig type t = M.t end)
Dreyer prohibits both programs, since, in both cases, underlying implementations of the types M.t and N.t make a cycle. We only prohibit the latter, since, according to the signatures, only the latter contains a cycle; in the former program, the types M.t and N.t are nothing more than abstract types. His choice may detect possible bugs in programs due to cyclic definitions, but results in restrictions on uses of structural types such as lists and tuples together with type abstraction5. The core language we want to support is that of Objective Caml, and we want to keep liberal uses of polymorphic variants (Garrigue, 1998) and objects, which are useful structural types supported in O’Caml.