|Anonymous | Login | Signup for a new account||2014-11-28 17:58 CET|
|Main | My View | View Issues | Change Log | Roadmap|
|View Issue Details|
|ID||Project||Category||View Status||Date Submitted||Last Update|
|0005905||OCaml||OCaml typing||public||2013-01-24 09:46||2013-12-17 05:00|
|Target Version||4.01.1+dev||Fixed in Version||4.02.0+dev|
|Summary||0005905: Allow to define explicit "impure" (i.e. generative) functors|
|Description||For some applications, not having the possibility to declare a functor as generative is a problem.|
For instance when you define a global map through a functor
module DB : functor (X : struct end) -> sig
let new_key : unit -> key
let write : key -> string -> unit
let read : key -> string
module MyDB = DB(struct end)
The above works fine (i.e. keys are restricted to a single DB) as long as nobody writes the following code:
module DB1 = DB(String)
module DB2 = DB(String)
which makes DB1.key and DB2.key equal.
The problem is that to my best knowledge there is no workaround.
My proposal is a rather stupid one: add some syntax for impure functors,
that are not using their argument, but must be generative.
module DB () = ...
module DB = functor () -> ...
module M = DB ()
module DB : functor () -> ...
Simplest implementation: all this is just syntactic sugar for an argument of name "*" and of type "sig end", and forcing the functor application to be generative in that case.
I agree it would be very nice to have generative functors in addition to transparent ones. But why should this notion require a "dummy" argument? It is quite common to have functors taking a non-trivial argument, which should be generative (typical example: a hash-consing functor). I'd rather have a different kind of functors (unfortunately, this requires more innovation on the syntactic side than your proposal).
Also, generative functors enable something very useful: unpacking of first-class modules within/as the functor body. This can be used, for instance, to choose at runtime between two implementations of the functor, based on some condition. With runtime types (or a manual version based on GADTs), it is even possible to customize the functor's behavior according to the structure of the abstract types in the argument (example: implement sets as Patricia trees if the elements are integers).
Would your proposal make this possible for generator functors?
The idea of using a "dummy" argument is that it requires no new syntax (or very little).
And it is just as expressive: you just have to add () as last argument to make your functor generative.
The discussion should rather be: since generativeness is a property of functors, is it useful to mark it in functor applications. I believe that this is the case, as this is the application, not the functor, that behaves differently.
I have also updated the patch so that it is now possible to unpack first class modules inside impure functors:
module type S = sig val x : int end;;
let v = (module struct let x = 3 end : S);;
module F() = (val v);;
|Fixed the patch: if we are to allow unpacking inside impure functors, then we should not allow applying them inside an applicative body...|
Fixed the patch again: one cannot coerce an impure functor into an applicative one.
The patch is in trunk/experimental/garrigue/impure-functors.diff
|FWIW, I believe that extending the language with generative functors would indeed be very useful, especially if it allows to unpack first-class modules in their body.|
|Now that 4.01 is branched, what about including the patch in the trunk? It seems nobody objects to it, and there are at least two supporters.|
|Jacques: do you think your patch is ready for inclusion, or are you aware of some problems with it?|
I don't recall any problem, but of course I would check everything again before inclusion.
Some parts may have to be discussed, since I tried to be the less intrusive as possible.
An example that should be prevented:
module F () : sig type t end = struct module M = (val ...) type t = M.t end
module G (X : struct end) : sig type t end = struct
module L = F ()
type t = L.t
module N1 = G(X)
module N2 = G(X)
where `...` is some first-class module expression.
This would have N1.t equal to N2.t even though they may be different types (because they come from unpacking a first-class module).
This is already taken care of:
module type S = sig val x : int end
let v = (module struct let x = 3 end : S)
module F() = (val v);;
# module G (X : sig end) : S = F ();;
Error: This kind of expression is only allowed inside impure functors.
edited on: 2013-11-15 13:05
This idea is only half-baked, but I was wondering if the same mechanism could be used to express functors that are only used for their side-effects. Something like:
module F (X : sig ... end) : () = struct
do some effectful thing
module () = F(Foo)
so the functor is given `()` as its return type, and `()` can only be given to the module expression `()`. So the following would be an error:
module M = F(Foo)
similarly, ignoring the result of a normal functor would be an error:
module () = Map.Make(List)
Note that since these side-effect only functors can not create any types, I think they can safely be used within an applicative functor even if they are "impure".
I'm not sure we need new syntax for the return type part.
But you're right on one point: if we now that a generative functor returns no types, then it should be safe to call it inside an applicative one.
Same thing applies to unpacking.
Both can be useful in practice.
Patch merged to trunk at revision 14365.
It allows opening first class modules and applying generative functors inside applicative functors, if no types are created.
|2013-01-24 09:46||garrigue||New Issue|
|2013-01-24 09:46||garrigue||File Added: impure-functors.diff|
|2013-01-24 10:21||frisch||Note Added: 0008791|
|2013-01-25 03:12||garrigue||File Deleted: impure-functors.diff|
|2013-01-25 03:12||garrigue||File Added: impure-functors.diff|
|2013-01-25 03:25||garrigue||Note Added: 0008795|
|2013-01-25 12:10||garrigue||File Deleted: impure-functors.diff|
|2013-01-25 12:10||garrigue||File Added: impure-functors.diff|
|2013-01-25 12:15||garrigue||Note Added: 0008798|
|2013-01-31 08:02||garrigue||File Deleted: impure-functors.diff|
|2013-01-31 08:04||garrigue||Note Added: 0008816|
|2013-05-21 15:17||frisch||Note Added: 0009314|
|2013-06-18 13:26||frisch||Note Added: 0009547|
|2013-06-18 15:53||doligez||Status||new => confirmed|
|2013-06-18 15:53||doligez||Target Version||=> 4.02.0+dev|
|2013-07-12 18:15||doligez||Target Version||4.02.0+dev => 4.01.1+dev|
|2013-09-20 18:37||frisch||Note Added: 0010383|
|2013-09-20 22:50||garrigue||Note Added: 0010386|
|2013-10-10 11:40||doligez||Tag Attached: patch|
|2013-10-10 11:51||lpw25||Note Added: 0010448|
|2013-11-13 07:28||garrigue||Note Added: 0010625|
|2013-11-15 13:03||lpw25||Note Added: 0010636|
|2013-11-15 13:05||lpw25||Note Edited: 0010636||View Revisions|
|2013-11-18 08:38||garrigue||Note Added: 0010638|
|2013-12-17 05:00||garrigue||Note Added: 0010734|
|2013-12-17 05:00||garrigue||Status||confirmed => resolved|
|2013-12-17 05:00||garrigue||Fixed in Version||=> 4.02.0+dev|
|2013-12-17 05:00||garrigue||Resolution||open => fixed|
|2013-12-17 05:00||garrigue||Assigned To||=> garrigue|
|Copyright © 2000 - 2011 MantisBT Group|