Closed charguer closed 9 years ago
Module types are structural not nominative, and this behaviour is consistent with that. The members of your module type should distinguish it from other module types.
You can achieve nominative behaviour using the following:
type foo
module type Foo = sig
type kind = foo
[...]
end
type bar
module type Bar = sig
type kind = bar
[...]
end
I also hope to at some point (probably before modular implicits) add private module types to OCaml (essentially the same as private types but for modules), which allows you to get nominative behaviour for module types.
Sounds great! Btw, do you have an up-to-date tutorial / collection of examples that covers (among other things) the nominative encoding?
Btw, do you have an up-to-date tutorial / collection of examples that covers (among other things) the nominative encoding?
I'm afraid not, it's definitely on the todo list, but probably won't get done for quite a while. The abstract from OCaml 2014 outlines basic usage but is quite short.
... and it does not mention the nominal vs structural matching, leaving me to believe that the approach could not work; now that I understand it, I find your proposal much more appealing.
If not writing a tutorial, I would suggest at the very least preparing an example module that shows how to set up proper overloading for all the basic arithmetic operators that every one would want to see overloaded (+, -, *, /, and perhaps also abs and mod). ---I say "everyone", assuming that inlining works well enough for this to be zero-cost. This module would have both direct practical application, and could serve as a little demo of your patch.
Btw, I would strongly encourage having one class per operator, instead of a "Num" class that tries to do everything at once. The reason is that the user may want to overload "+" on types (e.g. strings) where other operators don't make sense. Note that "Num" can be set up as a functor so as to allow providing instances for several operators at once, although in practice I don't think it's a big deal, plus it would require functor inlining to work to avoid the overhead.
Don't hesitate to let me know if you need help with such a library. + Arthur
If not writing a tutorial, I would suggest at the very least preparing an example module that shows how to set up proper overloading for all the basic arithmetic operators that every one would want to see overloaded (+, -, *, /, and perhaps also abs and mod). ---I say "everyone", assuming that inlining works well enough for this to be zero-cost. This module would have both direct practical application, and could serve as a little demo of your patch.
I agree that this is a very good idea. Fred had started some examples which I extracted to form the basis of an example library for implicits: https://github.com/ocamllabs/imp. I haven't had a chance to look at them since then, but would definitely appreciate help/pull requests for that.
If you do have a look at improving "Imp" feel free to experiment with the appropriate style because how best to use implicits in libraries is still something that we are working out as we go. Also feel free to suggest removing or adding modules to the library.
There may also be some things in the testsuite which could be useful to look at to see how implicits work.
Btw, I would strongly encourage having one class per operator, instead of a "Num" class that tries to do everything at once. The reason is that the user may want to overload "+" on types (e.g. strings) where other operators don't make sense. Note that "Num" can be set up as a functor so as to allow providing instances for several operators at once, although in practice I don't think it's a big deal, plus it would require functor inlining to work to avoid the overhead.
I agree, I think the Num
typeclass in Haskell is generally considered a mistake for similar reasons.
Don't hesitate to let me know if you need help with such a library.
Issues and pull requests to both this repository or the Imp repository are extremely welcome. Feel free to raise issues for questions as well as bugs.
(* a first class *)
module type Foo = sig type t val f : t -> t end
implicit module Foo_int = struct (* I'd like to specify that this is an instance for Foo *) type t = int let f x = x + 1 end
let foo_f (implicit P : Foo) x = P.f x
(* a first use case for foo *)
let a = foo_f 1
(* another, completely unrelated class *)
module type Bar = sig (* I'd like to specify that this is an instance for Bar *) type t val f : t -> t end
implicit module Bar_int = struct type t = int let f x = x + 2 end
let bar_f (implicit P : Bar) x = P.f x
(* now, a second use case for foo *)
let b = foo_f 1
(* I think there is a big modularity problem, here. the "implicit" instances should be tagged with the class to which they belong. Being isomorphic is not in my opinion the good criteria for belonging to the same class. *)