Replies: 3 comments 5 replies
-
|
I personally think it's more natural to have:
The modular explicit syntax is very natural because And the modular implicit syntax is natural for both anyone who knows a bit of Coq (see manual) and current OCaml users who might be familiar with first-class modules. Having the |
Beta Was this translation helpful? Give feedback.
-
|
Personally, I prefer designs which keep modular implicits and dependent module parameters separate, and treat dependent module parameters and first-class module parameters as closely related. One reason for this is that I think they will mostly be used for very different use cases, and be thought about by users very differently, with implicits thoughts about more like type-classes and dependent module parameters thoughts about more like ordinary parameters. Another reason is that I think it is worth exploring the design space where the thing you write after the colon in an implicit parameter is not an ordinary module type. I'm particularly interested in exploring designs that look something like: module type Set = sig
type t
type elt
val empty : t
val add : t -> elt -> t
[etc]
end
type class Set[type t] : Set with type elt = t
instance Set[string] := String.Set
instance Set[bool] := Bit_set
let singleton (type a) {S : Set[a]} s = S.add s S.emptywhich gives val singleton : {S : Set['a]} -> 'a -> S.tI like this kind of design for a couple of reasons:
I'm not saying we should definitely go in this direction, but I do think it is worth exploring, and it certainly pushes in the direction of thinking of implicits and dependent module parameters as quite different. |
Beta Was this translation helpful? Give feedback.
-
|
A variation on 2, could we reuse the Coq-like grouping of similar argument like we do for locally abstract types let f (type a b c) = ()to factorize the syntactic cost: let f (module (L:Label) (E: Edge with Label = L) (N:Node with E = Edge)) = () |
Beta Was this translation helpful? Give feedback.
Uh oh!
There was an error while loading. Please reload this page.
Uh oh!
There was an error while loading. Please reload this page.
-
Syntax questions around explicit and implicit module applications
I am working on Modular implicits, an experimental OCaml feature that is intended as a typeclass-like mechanism. The idea behind it is to have an implicit argument mechanism with module arguments. There remain important unsolved design questions around modular implicits and we don't expect them to be integrated in the language before at least a few years.
It has been suggested in the past to integrate modular explicits first, which permits writing module dependent functions without providing any implicit inference or elaboration. I believe that this is a nice idea, and am preparing a new PR to propose modular explicits for integration in the next few weeks/months.
There are thorny questions around the syntax we want for those features. We plan to propose only modular explicits at first, but we want to pick a syntax that integrates well with the language today, but will also integrate well with modular implicits proposed in the future.
In this post we propose to discuss the syntax for both (and related OCaml features) to have a better view of the (syntactic) design space. It presents 4 different syntaxes that I have heard about for modular explicits/implicits (the 4th being my favorite but the most complicated).
Proposal by Matthew Ryan
The first PR for modular explicits by M. Ryan proposed to reuse the syntax of modular implicits presented above for modular explicits:
let f {M : S} x ...for explicit module abstractions, andf {Int} foofor explicit module applications.The idea is that if we add modular implicits later, then all examples can be re-intepreted as modular implicits, and now providing explicit applications is optional -- explicit applications
f {Int} fooare still supported, but users can write justf fooand the module arguments gets (implicitly) elaborated.Problem: split between first-class modules and dependent module arguments
The main issue with this proposal is the split between first-class modules and dependent module arguments. The two features are very related (a function can take a module as parameter), but they have different syntaxes and different typing rules:
let f (module M : S) = bodycan receive any first-class module as argument, howeverMcannot appear in the type ofbodylet f {M : S} = bodymust receive a module expression at application, butMcan appear in the type ofbodyHow will non-expert users know which one to use ?
This problem was spotted by @EduardoRFS (see github or discuss).
On one hand we have first-class modules that are known by the community, they are a regular type of value but cannot be made dependent.
On the other hand there are modular explicits with a completely different syntax that will be brand new. It is not a value thus we cannot have a function that returns a module using this mechanism, but functions can be made dependent.
Ideally we could use a syntax for modular explicits that coincides with first-class modules, at least in the cases where both can be used, and yet integrates gracefully with modular implicits.
In order to think and discuss about this problem we will present and give arguments for and against various syntaxes for modular implicits and explicits.
1 - The initial proposal for modular implicits
In 2014 Leo White, FrΓ©dΓ©ric Bour and Jeremy Yallop proposed a syntax with brackets for implicit arguments :
Pros of this syntax :
Cons of this syntax :
2 - New proposal : Modular implicits as optional modular explicits
The idea here would be to use the syntax presented above for modular explicits as done by Matthew Ryan, but with labels to module arguments.
The idea being : if a module argument has an implicit label and is omitted we use the implicit inference mechanism to infer the module expression.
Pros:
Cons:
?symbol with a slightly different semantic (but we could choose a different symbol).~M,?Mcould be allowed?).3 - Removing the split: unioning first-class modules and dependent module arguments
The idea of this syntax would be to allow functions taking an argument that is an unpacking of a first-class module to be dependent.
For example :
For implicit abstractions we could use the
implicitkeyword:Pros :
Cons :
module/implicitkeyword everywhere)4 - New proposal : Both (2 + 3)
The idea here would be to have a mix of syntax 2 and 3 presented above. To put it simply all the examples above up to the
implicitkeyword would be accepted :{M : S}) (with labels for implicits).This would lead to 2 different incompatible syntax for passing module arguments to module-dependent functions. However, one would be strictly less expressive than the other but also the less verbose.
Pros :
Cons :
?symbol with a slightly different semantic (but we could choose a different symbol)Other possible extensions
When discussing syntax of modular explicits and modular implicits, syntax of other features could also be brought to your attention.
(Semi-)Explicit type arguments
It could be useful for readability to be able to give a type argument to a function. Using modular explicits we will be able to give a module containing exactly a type to a dependent function but not directly the type.
A way to solve this could be to reuse the syntax for modular implicits presented above with braces or labels + braces and use this for type arguments :
Such a mechanism would be a way to receive polymorphic arguments when writing a function.
We could also offer this with the
implicitkeyword or with labelled arguments:Signatures parametrized over a type
With modular implicits/explicits we could need to write a function demanding multiple modules with the same type.
However, this can become pretty verbose. A fix for this would be to allow parametric signatures because we know that those signatures will (almost) always be used with a
with type t = ....This would allow us to write a much more compact code.
However, this poses a few questions :
Add(E.t)or maybeAdd(type E.t)orE.t Add?module Eq (type t) = type val eq : t -> t -> bool end?module type t Eq = type val eq : t -> t -> bool end?Beta Was this translation helpful? Give feedback.
All reactions