* [Caml-list] Explicitely named type variable and type constraints. @ 2012-03-21 7:48 Philippe Veber 2012-03-21 8:21 ` Jacques Garrigue 0 siblings, 1 reply; 6+ messages in thread From: Philippe Veber @ 2012-03-21 7:48 UTC (permalink / raw) To: caml users [-- Attachment #1: Type: text/plain, Size: 1778 bytes --] Hi, I found myself defining a type that would both contain a module type and a type constraint: module type Screen = sig type state type message val init : state [...] val emit : state -> message option end type 'a screen = (module Screen with type message = 'a) constraint 'a = [> `quit] That is supposed to express that screens emit messages, and that one of the messages can be "quit". Now I've got some trouble when using the 'a screen type in a function that unpack the module it contains: let f (screen : 'a screen) = let module Screen = (val *screen* : Screen) in match Screen.(emit init) with | Some `quit -> 1 | _ -> 0 ;; Error: This expression has type ([> `quit ] as 'a) screen = (module Screen with type message = 'a) but an expression was expected of type (module Screen) New attempt: # let f (screen : 'a screen) = let module Screen = (val screen : Screen with type message = 'a) in match Screen.(emit init) with | Some `quit -> 1 | _ -> 0 ;; Error: Unbound type parameter 'a Though here I'm not sure the error is right. New attempt: # let f (type s) (screen : s screen) = let module Screen = (val screen : Screen with type message = s) in match Screen.(emit init) with | Some `quit -> 1 | _ -> 0 ;; Error: This type s should be an instance of type [> `quit ] Which makes sense. So here is my question: is there a way to impose a constraint on the "newtype" introduced in argument? Let me say that I'm aware I should write this more simply. For instance in the module type Screen, emit could have type state -> [`quit | `message of message]. So my question is only a matter of curiosity. Still, I'd be happy to know :o). Cheers, Philippe. [-- Attachment #2: Type: text/html, Size: 5502 bytes --] ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [Caml-list] Explicitely named type variable and type constraints. 2012-03-21 7:48 [Caml-list] Explicitely named type variable and type constraints Philippe Veber @ 2012-03-21 8:21 ` Jacques Garrigue 2012-03-21 8:54 ` Alan Schmitt 2012-03-21 9:41 ` Philippe Veber 0 siblings, 2 replies; 6+ messages in thread From: Jacques Garrigue @ 2012-03-21 8:21 UTC (permalink / raw) To: Philippe Veber; +Cc: caml users On 2012/03/21, at 16:48, Philippe Veber wrote: > Hi, > > I found myself defining a type that would both contain a module type and a type constraint: > > module type Screen = sig > type state > type message > val init : state > [...] > val emit : state -> message option > end > type 'a screen = (module Screen with type message = 'a) constraint 'a = [> `quit] > > That is supposed to express that screens emit messages, and that one of the messages can be "quit". Now I've got some trouble when using the 'a screen type in a function that unpack the module it contains: > > let f (screen : 'a screen) = > let module Screen = (val screen : Screen) in > match Screen.(emit init) with > | Some `quit -> 1 > | _ -> 0 > > ;; > Error: This expression has type > ([> `quit ] as 'a) screen = (module Screen with type message = 'a) > but an expression was expected of type (module Screen) Indeed, this is clearly wrong: these two module types are not equivalent. > New attempt: > > # let f (screen : 'a screen) = > let module Screen = (val screen : Screen with type message = 'a) in > match Screen.(emit init) with > | Some `quit -> 1 > | _ -> 0 > > ;; > Error: Unbound type parameter 'a Wrong again, as subtyping between module signatures does not allow free type variables. > Though here I'm not sure the error is right. New attempt: > > > # let f (type s) (screen : s screen) = > let module Screen = (val screen : Screen with type message = s) in > match Screen.(emit init) with > | Some `quit -> 1 > | _ -> 0 > > ;; > Error: This type s should be an instance of type [> `quit ] > > Which makes sense. So here is my question: is there a way to impose a constraint on the "newtype" introduced in argument? Let me say that I'm aware I should write this more simply. For instance in the module type Screen, emit could have type state -> [`quit | `message of message]. So my question is only a matter of curiosity. Still, I'd be happy to know :o). No, currently there is no way to do that. One can only create locally abstract types, not locally private types. In theory I see no problem doing that, but with the current approach this would require new syntax, and be rather heavy. let f (type s = private [> `quit]) (screen : s screen) = ... And to be fully general, recursion between those types should be allowed too... As a side note, writing type message = private [> unit] makes the problem clearer. And solves it in some cases: module type Screen = sig type state type message = private [> `quit ] val init : state val emit : state -> message option end # let f (module Screen : Screen) = match Screen.(emit init) with | Some `quit -> 1 | _ -> 0 ;; val f : (module Screen) -> int = <fun> (using 4.00, but you can also write with (val ...)) Jacques Garrigue ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [Caml-list] Explicitely named type variable and type constraints. 2012-03-21 8:21 ` Jacques Garrigue @ 2012-03-21 8:54 ` Alan Schmitt 2012-03-21 9:01 ` Thomas Braibant 2012-03-21 9:41 ` Philippe Veber 1 sibling, 1 reply; 6+ messages in thread From: Alan Schmitt @ 2012-03-21 8:54 UTC (permalink / raw) To: caml users On 21 mars 2012, at 09:21, Jacques Garrigue wrote: > (using 4.00, but you can also write with (val …)) Nice teaser ;-) Alan ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [Caml-list] Explicitely named type variable and type constraints. 2012-03-21 8:54 ` Alan Schmitt @ 2012-03-21 9:01 ` Thomas Braibant 2012-03-21 9:29 ` Alain Frisch 0 siblings, 1 reply; 6+ messages in thread From: Thomas Braibant @ 2012-03-21 9:01 UTC (permalink / raw) To: Alan Schmitt; +Cc: caml users On Wed, Mar 21, 2012 at 9:54 AM, Alan Schmitt <alan.schmitt@polytechnique.org> wrote: > On 21 mars 2012, at 09:21, Jacques Garrigue wrote: > >> (using 4.00, but you can also write with (val …)) > > Nice teaser ;-) > Indeed, this is the second time I see an OCaml 4.00 mentionned (once here, and once on the OCamlPro webpage, with an ETA ;)). Is it the same future version of OCaml as the former 3.13, or is it something different ? Thomas ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [Caml-list] Explicitely named type variable and type constraints. 2012-03-21 9:01 ` Thomas Braibant @ 2012-03-21 9:29 ` Alain Frisch 0 siblings, 0 replies; 6+ messages in thread From: Alain Frisch @ 2012-03-21 9:29 UTC (permalink / raw) To: Thomas Braibant; +Cc: Alan Schmitt, caml users On 03/21/2012 10:01 AM, Thomas Braibant wrote: > On Wed, Mar 21, 2012 at 9:54 AM, Alan Schmitt > <alan.schmitt@polytechnique.org> wrote: >> On 21 mars 2012, at 09:21, Jacques Garrigue wrote: >> >>> (using 4.00, but you can also write with (val …)) >> >> Nice teaser ;-) >> > > Indeed, this is the second time I see an OCaml 4.00 mentionned (once > here, and once on the OCamlPro webpage, with an ETA ;)). > > Is it the same future version of OCaml as the former 3.13, or is it > something different ? There is no mystery here. From http://caml.inria.fr/cgi-bin/viewvc.cgi/ocaml/version/ you can see that: - The 3.12 branch has been closed. - A new 4.00 branch has been created. -- Alain ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [Caml-list] Explicitely named type variable and type constraints. 2012-03-21 8:21 ` Jacques Garrigue 2012-03-21 8:54 ` Alan Schmitt @ 2012-03-21 9:41 ` Philippe Veber 1 sibling, 0 replies; 6+ messages in thread From: Philippe Veber @ 2012-03-21 9:41 UTC (permalink / raw) To: Jacques Garrigue; +Cc: caml users [-- Attachment #1: Type: text/plain, Size: 5187 bytes --] Thanks for your answer Jacques! > ([> `quit ] as 'a) screen = (module Screen with type message = > 'a) > > but an expression was expected of type (module Screen) > > Indeed, this is clearly wrong: these two module types are not equivalent. > Right, that one was obvious. > > New attempt: > > > > # let f (screen : 'a screen) = > > let module Screen = (val screen : Screen with type message = 'a) in > > match Screen.(emit init) with > > | Some `quit -> 1 > > | _ -> 0 > > > > ;; > > Error: Unbound type parameter 'a > > Wrong again, as subtyping between module signatures does not > allow free type variables. > At some point, I remember having a message saying that indeed type variables are not allowed while unpacking the module, at least something closer to what you say and more specific than "unbound type parameter 'a". So I'd say it would be more convenient to have a specific message (just like there is for unbound type variables in class definitions for instance). If you don't consider it too futile, I can test it on the SVN head and file a bug report if appropriate. > > > Though here I'm not sure the error is right. New attempt: > > > > > > # let f (type s) (screen : s screen) = > > let module Screen = (val screen : Screen with type message = s) in > > match Screen.(emit init) with > > | Some `quit -> 1 > > | _ -> 0 > > > > ;; > > Error: This type s should be an instance of type [> `quit ] > > > > Which makes sense. So here is my question: is there a way to impose a > constraint on the "newtype" introduced in argument? Let me say that I'm > aware I should write this more simply. For instance in the module type > Screen, emit could have type state -> [`quit | `message of message]. So my > question is only a matter of curiosity. Still, I'd be happy to know :o). > > No, currently there is no way to do that. > One can only create locally abstract types, not locally private types. > Ok. > In theory I see no problem doing that, but with the current approach this > would require new syntax, > and be rather heavy. > > let f (type s = private [> `quit]) (screen : s screen) = ... > > And to be fully general, recursion between those types should be allowed > too... > Probably not worth the trouble. I'm just not used to writing a type and not being able to write a function using values of this type afterwards :o). > > As a side note, writing > type message = private [> unit] > makes the problem clearer. > And solves it in some cases: > > module type Screen = > sig > type state > type message = private [> `quit ] > val init : state > val emit : state -> message option > end > # let f (module Screen : Screen) = > match Screen.(emit init) with > | Some `quit -> 1 > | _ -> 0 > ;; > val f : (module Screen) -> int = <fun> > Indeed that works! (with appropriate 3.12 syntax). # module type Screen = sig type state type message = private [> `quit ] val init : state val emit : state -> message option end;; module type Screen = sig type state type message = private [> `quit ] val init : state val emit : state -> message option end # let f screen = let module Screen = (val screen : Screen) in match Screen.emit Screen.init with Some `quit -> 1 | _ -> 0;; val f : (module Screen) -> int = <fun> # module Screen1 : Screen = struct type state = unit type message = [`a | `quit] let init = () let emit () = Some `a end;; module Screen1 : Screen # module Screen2 : Screen = struct type state = int type message = [`a | `quit] let init = 0 let emit _ = Some `quit end;; module Screen2 : Screen # [ (module Screen1 : Screen) ; (module Screen2 : Screen) ];; - : (module Screen) list = [<module>; <module>] This nearly solves my problem: there will be several Screen modules, and those should share a common message type, so that they can communicate. That's why I introduced the 'a screen type. However, it seems that I can't define it anymore: # type 'a screen = (module Screen with type message = 'a) constraint 'a = [> `quit];; Error: In this `with' constraint, the new definition of message does not match its original definition in the constrained signature: Type declarations do not match: type message is not included in type message = private [> `quit ] # type 'a screen = (module Screen with type message = 'a constraint 'a = [> `quit]);; Error: Syntax error It's only logical the first attempt fails. The second, however, seems more reasonable to me (but I guess if type constraints are only allowed in type definition there must be a good reason). Is there a workaround? In the end, I'd want to define a list of Screen modules that share a common message type containing the `quit tag. That said, I remember the work by Romain Bardou and yourself on unions of private polymorphic variants, and I guess we might face difficult problems here. In any case, I have a backup solution, so it's no big deal if it isn't possible. > (using 4.00, but you can also write with (val ...)) > > That remark was unfortunate: now my thread is spoiled for sure :o))) [-- Attachment #2: Type: text/html, Size: 10104 bytes --] ^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2012-03-21 9:42 UTC | newest] Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2012-03-21 7:48 [Caml-list] Explicitely named type variable and type constraints Philippe Veber 2012-03-21 8:21 ` Jacques Garrigue 2012-03-21 8:54 ` Alan Schmitt 2012-03-21 9:01 ` Thomas Braibant 2012-03-21 9:29 ` Alain Frisch 2012-03-21 9:41 ` Philippe Veber
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox