Mantis Bug Tracker

View Issue Details Jump to Notes ] Issue History ] Print ]
IDProjectCategoryView StatusDate SubmittedLast Update
0005905OCamlOCaml typingpublic2013-01-24 09:462013-12-17 05:00
Reportergarrigue 
Assigned Togarrigue 
PrioritynormalSeverityfeatureReproducibilityalways
StatusresolvedResolutionfixed 
PlatformOSOS Version
Product Version4.01.0+dev 
Target Version4.01.1+devFixed in Version4.02.0+dev 
Summary0005905: Allow to define explicit "impure" (i.e. generative) functors
DescriptionFor 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
      type key
      let new_key : unit -> key
      let write : key -> string -> unit
      let read : key -> string
   end

   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.
Patch included.
Tagspatch
Attached Files

- Relationships

-  Notes
(0008791)
frisch (developer)
2013-01-24 10:21

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?
(0008795)
garrigue (manager)
2013-01-25 03:25

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);;
(0008798)
garrigue (manager)
2013-01-25 12:15

Fixed the patch: if we are to allow unpacking inside impure functors, then we should not allow applying them inside an applicative body...
(0008816)
garrigue (manager)
2013-01-31 08:04

Fixed the patch again: one cannot coerce an impure functor into an applicative one.
The patch is in trunk/experimental/garrigue/impure-functors.diff
(0009314)
frisch (developer)
2013-05-21 15:17

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.
(0009547)
frisch (developer)
2013-06-18 13:26

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.
(0010383)
frisch (developer)
2013-09-20 18:37

Jacques: do you think your patch is ready for inclusion, or are you aware of some problems with it?
(0010386)
garrigue (manager)
2013-09-20 22:50

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.
(0010448)
lpw25 (developer)
2013-10-10 11:51

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
  end

  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).
(0010625)
garrigue (manager)
2013-11-13 07:28

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.
(0010636)
lpw25 (developer)
2013-11-15 13:03
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
    ...
  end

  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".

(0010638)
garrigue (manager)
2013-11-18 08:38

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.
(0010734)
garrigue (manager)
2013-12-17 05:00

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.

- Issue History
Date Modified Username Field Change
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
Powered by Mantis Bugtracker