-
Notifications
You must be signed in to change notification settings - Fork 32
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
include functor
#43
base: master
Are you sure you want to change the base?
include functor
#43
Conversation
In a similar way could we also add a This might be useful in some other cases and does not seem much work in addition to this feature. The use case that I have in mind would be linked to modular implicits : module type Eq = sig
type t
val eq : t -> t -> bool
end
module type Ord = sig
type t
val cmp : t -> t -> int
module E : Eq with type t = t
end
module F (X : sig type t val ord : t -> t -> int) : Ord with type t = X.t = body
module OInt = struct
type t = int
let cmp = Int.compare
module functor E = F
end This allows for the |
Indeed. I agree this is a reasonable feature and not much more work. It has occasionally been requested by users of |
This is a pattern that is actually quite common in the flambda2 code base, in particular module T = struct
module M = struct
type t = ...
let compare = ...
end
include M
module Set = Set.Make(M)
end Which would allow to get rid of that spurious module T = struct
type t = ...
let compare = ...
module functor Set = Set.Make
end One such example in the upstream compiler code base: |
Have you considered the alternative of giving a name (say " module M = struct
type t = ...
[@@deriving compare, sexp]
include functor Comparable.Make
end you'd write module M = struct
type t = ...
[@@deriving compare, sexp]
include Comparable.Make(_)
end ? With that alternative design it'd be possible to refer to the module prefix in arbitrary module expressions rather than always passing it as the argument of a single-parameter functor, so you could also write things like: include F(_)(X) and module type of _ and open F(_) and module E = F(_) and include S with module type T = _ and perhaps even type t = F(_).t etc. |
Just to be sure : do the components used to "fill in" the parameter need to be defined from the current structure, or do they only need to be visible at this point (coming from a surrounding structure or from some |
A better argument against using underscore to talk about the beginning of the module is that current work on modular implicits. We are currently thinking of defining |
They need to be defined from the current structure. One could imagine doing either thing, but this has a nice clear rule, makes it less likely refactorings will cause errors due to what is in scope for include functor changing, and simplifies the implementation. |
For syntax, we could use use just plain old
Or we could be even bolder and use a symbol:
I think any syntax should not be available in paths. |
Personally, I dislike both the: module functor E = F form and mechanisms based on a name for the contents of the current module, and would prefer to push people towards sig
type t
module Set : Set.S with type elt = t
end and use that, rather than having each user choose the name for their set module.
module type MixS = (X : OrderedType) -> sig module Set : S with type elt = X.t end
module Mix : MixS and then you can write: module Foo : sig
type t
include functor Set.MixS
end = struct
type t = [...]
let compare = [...]
include functor Set.Mix
end |
If I understand correctly, this use of |
That is one way to look at it and it does look different from other uses of module types in that perspective. An alternative though is to consider |
If I understand correctly, module F = functor (Y:S) -> struct (* ... *) end
module Foo = struct
(* code *)
include functor F
end could be replaced by changing module F = functor (Y:S) -> struct include Y (* ... *) end
module Foo = F(struct
(* code *)
end) Overall, could the role of |
I think this is a reasonable idea, but doesn't quite offer the full convenience of module M = struct
module T = struct
type t = ...
[@@deriving compare, sexp]
end
include T
include Comparable.Make(T)
end I think your proposal saves the |
It can save struct
open (struct module X = M end)
include X
include F(X)
end Then the example of the RFC would become: module M = Comparable.Make [reexport] (struct
type t = ...
[@@ deriving compare, sexp]
end) I think it provides more or less the same functionality. An upside is that it does not depend on a specific position in the code like module M = struct
type t = ...
include functor F
let x = 42
include functor G
end |
Actually a key issue with the re-export pattern I was suggesting is that the functor can only re-export the field indicated in its parameter signature, which seems much more restricted than |
This is a proposal for a new structure and signature item form,
include functor
.Rendered version
(Thanks to @OlivierNicole and @goldfirere for help preparing this RFC)