Since the last meeting, we have written a rather lengthy presentation of “modular explicits”, and their interaction with the rest of the language. You can find that technical document at http://pourquoi.parce-q.eu/modular-explicits.pdf
Here we will only give a very brief reminder of what the proposal is, and discuss the questions and concerns that were raised at the last meeting. For everything else, we refer the reader to the technical document.
The “modular explicits” project proposes to extend the core language with module-dependent functions, concretely this means:
{M:S} -> type_expr, where the type expression on the right of the arrow can refer to M, a module of type S bound on the left of the arrowfun {X:S} -> expr, which constructs a module-dependent function, of type {X:S} -> _e {M}, to eliminate module-dependent functionsThis construction gives access to the following features from the core-language:
To get a feel for module-dependent functions, we reproduce here a canonical example: a map function parametrized by a monad:
module type Monad = sig
type _ t
val return : 'a -> 'a t
val bind : ('a -> 'b t) -> 'a t -> 'b t
end
let map {M : Monad} f (x : 'a M.t) : 'b M.t =
M.bind (fun x -> M.return (f x)) xSection 2 of the technical document contains more detailed examples for each of the features listed above, as well as a description of a lightweight encoding of Fω in OCaml using module-dependent functions.
We refer to section 1 of the extended technical document for a (more) serious description of the construction and its semantics.
Here we limit ourselves to reminding everyone of the intuition given by the modular implicits paper: a module-dependent function is just a lightweight syntax for manipulating first-class functors.
The overlap between module-dependent functions and (a particular use of) first-class modules has been pointed out by several people, raising the question of the usefulness of the construction, and the potential confusion for users of the language between it and what already exists.
The said overlap happens between module-dependent functions which are not actually dependent and regular functions taking a first-class module as argument.
Both constructions do indeed behave in the same way in these situations, and could be used interchangeably. We show in the document (sec 3.2.3) that we can actually use module-dependent functions to write generic coercions between the two. We could in fact directly instruct to typechecker that they are convertible, that is, tell the compiler to treat types up to the following equivalence rule:
X \notin FTV(t)
-----------------------------------
|- {X : S} -> t === (module S) -> t
Furthermore, we explore in the document (sec 3.3) the idea of using the same syntax for both module-dependent functions, as we do for functions taking first-class module as arguments.
Going back to the map example above, it is conceivable to allow writing it as follows:
let map (module M : Monad) f (x : 'a M.t) : _ M.t =
M.bind (fun x -> M.return (f x)) xwhich would be given the type
val map : (module M : Monad) -> ('a -> 'b) -> 'a M.t -> 'b M.tand can be applied like so:
map (module Option) succ NoneThis is technically feasible (details are provided in the document) and, at first glance, hides the overlap between the two constructions: there is, syntactically, just one construction.
However, despite the syntax, the two constructions remain separate, and one cannot for instance, write the following
let f (x, (module M : Some_sig)) = some_exprand hope to have the type of some_expr depend on M.
The question of whether to use the same syntax for both constructions, or to have two different syntactic construct is still open. We (Didier and Thomas) lean towards keeping them syntactically separate, while allowing (explicit?) coercions between the two for cases which are compatible.
However decisions about syntax seem to be more a matter of taste (or intuition about good language design) than anything else. So we are expecting to hear your opinion on the matter.
Another question that was raised previously is whether modular-dependent functions are useful enough that it would be worth adding them to the language, even if we do not add modular implicits later on.
We believe that modular-dependent functions significantly extend the expressive power of the language. The examples we have looked at (and which we discuss in the document) also show a clear difference in usage between this new construction and first-class modules. The intersection of features is a concern for a few simple cases, and otherwise the two features do rather different things. Furthermore, some language support to move more easily between the two could be provided.
We also direct the reader to the technical document for a comprehensive discussion regarding the relationship between module-dependent functions and modular implicits.