* [Caml-list] phantom types and identity function @ 2012-11-27 11:00 Ivan Gotovchits 2012-11-27 14:08 ` Jacques Garrigue 0 siblings, 1 reply; 7+ messages in thread From: Ivan Gotovchits @ 2012-11-27 11:00 UTC (permalink / raw) To: caml-list Hello, These simple signature module type T = sig type 'a t constraint 'a = [< `A | `B ] val init: [`A] t val f: [`A] t -> [`B] t end can be used to constrain the following module module T : T = struct type 'a t = unit constraint 'a = [< `A | `B] let init = () let f x = x end where identity function successfully satisfies the constraint [`A] t -> [`B] t but in the following module module T : T = struct type 'a t = {x:int} constraint 'a = [< `A | `B] let init = {x=0} let f x = x end the same identity function doesn't satisfy. I'll be genuinelly happy, if somebody clarify this issue for me :) My guess is that the problem lies in the field of higher order polymorpism, and instead the identity function with signature 'a -> 'a, a more polymorphic function 'a -> 'b should be used. Though this contradicts with the fact that the identity function works fine in the first example and brings up another problem, which is how to obtain such polymorphic function... Thanks in advance! -- (__) (oo) /------\/ / | || * /\---/\ ~~ ~~ ...."Have you mooed today?"... ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [Caml-list] phantom types and identity function 2012-11-27 11:00 [Caml-list] phantom types and identity function Ivan Gotovchits @ 2012-11-27 14:08 ` Jacques Garrigue 2012-11-27 15:59 ` Gabriel Scherer 2012-11-28 3:29 ` Ivan Gotovchits 0 siblings, 2 replies; 7+ messages in thread From: Jacques Garrigue @ 2012-11-27 14:08 UTC (permalink / raw) To: Ivan Gotovchits; +Cc: caml-list On 2012/11/27, at 20:00, Ivan Gotovchits <ivg@ieee.org> wrote: > > Hello, > > These simple signature > > module type T = sig > type 'a t constraint 'a = [< `A | `B ] > val init: [`A] t > val f: [`A] t -> [`B] t > end > > can be used to constrain the following module > > module T : T = struct > type 'a t = unit constraint 'a = [< `A | `B] > let init = () > let f x = x > end > > where identity function successfully satisfies the constraint > > [`A] t -> [`B] t > > but in the following module > > module T : T = struct > type 'a t = {x:int} constraint 'a = [< `A | `B] > let init = {x=0} > let f x = x > end > > the same identity function doesn't satisfy. In the first case, a type abbreviation is used. Since ('a t) expands to (unit), the parameter is completely ignored, so that you can replace it by anything. In the second case, you define a concrete type, so that the parameter is not forgotten. Note that you cannot even use subtyping for that: let f x = (x : [`A] t :> [`B] t) fails too. But there is an easy workaround, defining in two steps: type u = {x:int} type 'a t = u constraint 'a = [< `A | `B] Jacques Garrigue ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [Caml-list] phantom types and identity function 2012-11-27 14:08 ` Jacques Garrigue @ 2012-11-27 15:59 ` Gabriel Scherer 2012-11-28 3:42 ` Ivan Gotovchits 2012-11-28 3:29 ` Ivan Gotovchits 1 sibling, 1 reply; 7+ messages in thread From: Gabriel Scherer @ 2012-11-27 15:59 UTC (permalink / raw) To: Jacques Garrigue; +Cc: Ivan Gotovchits, caml-list I have been a bit confused by this discussion, and found the relevant part of the manual that may enlighten other list readers: The OCaml Language, Type and exception definitions http://caml.inria.fr/pub/docs/manual-ocaml/manual016.html#toc54 "If the type has either a representation or an equation, and the parameter is free (i.e. not bound via a type constraint to a constructed type), its variance constraint is checked but subtyping etc. will use the inferred variance of the parameter, which may be better; otherwise (i.e. for abstract types or non-free parameters), the variance must be given explicitly, and the parameter is invariant if no variance was given." Note that this would not be needed if we had an explicit way to express the variance of invariant (the variable appears in both positive and negative positions) and irrelevant (the variable doesn't appear except in irrelevant positions) explicitly. We could then write, say: type 0'a t = {x : int} constraint 'a = [< `A | `B ] The absence of such a variance marker means that some OCaml code is hard to abstract through a module boundary: in presence of the explicit definition, the type-checker will accept to subtype between any instances of the type (by simple expansion), but if you abstract over its definition you cannot express this property anymore. Your workaround corresponds to statically expressing this irrelevance through an exported equation, but there are (arguably somewhat unnatural) scenarios where this isn't convenient. On Tue, Nov 27, 2012 at 3:08 PM, Jacques Garrigue <garrigue@math.nagoya-u.ac.jp> wrote: > > On 2012/11/27, at 20:00, Ivan Gotovchits <ivg@ieee.org> wrote: > > > > > Hello, > > > > These simple signature > > > > module type T = sig > > type 'a t constraint 'a = [< `A | `B ] > > val init: [`A] t > > val f: [`A] t -> [`B] t > > end > > > > can be used to constrain the following module > > > > module T : T = struct > > type 'a t = unit constraint 'a = [< `A | `B] > > let init = () > > let f x = x > > end > > > > where identity function successfully satisfies the constraint > > > > [`A] t -> [`B] t > > > > but in the following module > > > > module T : T = struct > > type 'a t = {x:int} constraint 'a = [< `A | `B] > > let init = {x=0} > > let f x = x > > end > > > > the same identity function doesn't satisfy. > > In the first case, a type abbreviation is used. > Since ('a t) expands to (unit), the parameter is completely > ignored, so that you can replace it by anything. > > In the second case, you define a concrete type, > so that the parameter is not forgotten. > Note that you cannot even use subtyping for that: > let f x = (x : [`A] t :> [`B] t) > fails too. > But there is an easy workaround, defining in two steps: > type u = {x:int} > type 'a t = u constraint 'a = [< `A | `B] > > Jacques Garrigue > > -- > Caml-list mailing list. Subscription management and archives: > https://sympa.inria.fr/sympa/arc/caml-list > Beginner's list: http://groups.yahoo.com/group/ocaml_beginners > Bug reports: http://caml.inria.fr/bin/caml-bugs ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [Caml-list] phantom types and identity function 2012-11-27 15:59 ` Gabriel Scherer @ 2012-11-28 3:42 ` Ivan Gotovchits 2012-11-28 8:12 ` Gabriel Scherer 0 siblings, 1 reply; 7+ messages in thread From: Ivan Gotovchits @ 2012-11-28 3:42 UTC (permalink / raw) To: Gabriel Scherer; +Cc: Jacques Garrigue, caml-list Gabriel Scherer <gabriel.scherer@gmail.com> writes: > The absence of such a variance marker means that some OCaml code is > hard to abstract through a module boundary: in presence of the > explicit definition, the type-checker will accept to subtype between > any instances of the type (by simple expansion), but if you abstract > over its definition you cannot express this property anymore. Your > workaround corresponds to statically expressing this irrelevance > through an exported equation, but there are (arguably somewhat > unnatural) scenarios where this isn't convenient. And now I'm confused much more =). Please, could you explain the relevance between subtyping and type restriction? When I try to restrict type [t -> t'] by the some type [r -> r'] does the compiler checks that [r -> r'] is a subtype of [t -> t']? And even if it does, in my example [`A] t -> [`B] t [[`A]] is clearly not a subtype of [[`B]] (and vice versa). So I do not see how an explicit variance specification can help. -- (__) (oo) /------\/ / | || * /\---/\ ~~ ~~ ...."Have you mooed today?"... ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [Caml-list] phantom types and identity function 2012-11-28 3:42 ` Ivan Gotovchits @ 2012-11-28 8:12 ` Gabriel Scherer 2012-11-28 10:32 ` Ivan Gotovchits 0 siblings, 1 reply; 7+ messages in thread From: Gabriel Scherer @ 2012-11-28 8:12 UTC (permalink / raw) To: Ivan Gotovchits; +Cc: Jacques Garrigue, caml-list On Wed, Nov 28, 2012 at 4:42 AM, Ivan Gotovchits <ivg@ieee.org> wrote: > And now I'm confused much more =). Please, could you explain the > relevance between subtyping and type restriction? I was reacting mostly to Jacques' remark that "you cannot even use subtyping for that". The relation between subtyping and "constraint" is as explained in the manual excerpt I quoted. The following is valid: type 'a t = {x : 'a} ;; let f x = (x : [ `A ] t :> [ `A | `B ] t);; but the following is not: type 'a t = {x : 'a} constraint 'a = [< `A | `B ];; let f x = (x : [ `A ] t :> [ `A | `B ] t);; Error: Type [ `A ] t is not a subtype of [ `A | `B ] t The first variant type does not allow tag(s) `B The reason for this behavior is that in the first case, t was inferred covariant, while the presence of a constraint disables variance inference (in the manual: "otherwise (ie. [...] for non-free parameters) the variance must be given explicitly)"). You can make the constrained version work with an explicit variance annotation: type +'a t = {x : 'a} constraint 'a = [< `A | `B ];; let f x = (x : [ `A ] t :> [ `A | `B ] t);; Finally, while in this example 'a occurs positively in ('a t), in your example 'a did not occur at all. In this case it is correct to coerce from (foo t) to (bar t), whatever the type expression (foo) and (bar) are -- they don't need to be in a subtyping relation. The following works: type 'a t = { x : int };; let f x = (x : [ `A ] t :> [ `B ] t);; I'm calling this form of variance "irrelevant" to highlight that the parameter can simply be ignored when checking for subtyping (some people call it "nonvariant", but it's kind of awkward if you already use "invariant" for the opposite notion of appearing both in positive and negative position). The OCaml type checker can use some restricted form of it (eg. the previous example), but you cannot abstract over it: there is no variance annotation to express that. Jacques' workaround replaces the definition of a new constrained type with a constrained type synonym, that is not checked using variance but direct expansion. But that works because you know what the definition expands to. In general there may be situation when you want to say "type 'a t, where 'a is not used" but not expose a (potentially abstract) non-parametrized type u such that "type 'a t = u". While we're at it: are you sure you need to play with phantom polymorphic variant types now that we have GADTs? I have used phantom types in the past, but my personal use cases would be profitably rewritten using GADTs. They tend to produce hairy error messages, but phantom polymorphic variants are not better in this regard. ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [Caml-list] phantom types and identity function 2012-11-28 8:12 ` Gabriel Scherer @ 2012-11-28 10:32 ` Ivan Gotovchits 0 siblings, 0 replies; 7+ messages in thread From: Ivan Gotovchits @ 2012-11-28 10:32 UTC (permalink / raw) To: Gabriel Scherer; +Cc: Jacques Garrigue, caml-list Gabriel Scherer <gabriel.scherer@gmail.com> writes: > The reason for this behavior is that in the first case, t was inferred > covariant, while the presence of a constraint disables variance > inference (in the manual: "otherwise (ie. [...] for non-free > parameters) the variance must be given explicitly)"). You can make the > constrained version work with an explicit variance annotation: > type +'a t = {x : 'a} constraint 'a = [< `A | `B ];; > let f x = (x : [ `A ] t :> [ `A | `B ] t);; Well, now I understand this. Thanks! > While we're at it: are you sure you need to play with phantom > polymorphic variant types now that we have GADTs? I have used phantom > types in the past, but my personal use cases would be profitably > rewritten using GADTs. They tend to produce hairy error messages, but > phantom polymorphic variants are not better in this regard. I wish I could, but I'm bond to Ocaml 3.11 =( -- (__) (oo) /------\/ / | || * /\---/\ ~~ ~~ ...."Have you mooed today?"... ^ permalink raw reply [flat|nested] 7+ messages in thread
* Re: [Caml-list] phantom types and identity function 2012-11-27 14:08 ` Jacques Garrigue 2012-11-27 15:59 ` Gabriel Scherer @ 2012-11-28 3:29 ` Ivan Gotovchits 1 sibling, 0 replies; 7+ messages in thread From: Ivan Gotovchits @ 2012-11-28 3:29 UTC (permalink / raw) To: Jacques Garrigue; +Cc: caml-list Jacques Garrigue <garrigue@math.nagoya-u.ac.jp> writes: > type u = {x:int} > type 'a t = u constraint 'a = [< `A | `B] Thanks Jacques, this workaround works fine! By the way, I've found another workaround, which dirty of course, but interesting: let f x = {x=x.x} works too. ^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2012-11-28 10:32 UTC | newest] Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2012-11-27 11:00 [Caml-list] phantom types and identity function Ivan Gotovchits 2012-11-27 14:08 ` Jacques Garrigue 2012-11-27 15:59 ` Gabriel Scherer 2012-11-28 3:42 ` Ivan Gotovchits 2012-11-28 8:12 ` Gabriel Scherer 2012-11-28 10:32 ` Ivan Gotovchits 2012-11-28 3:29 ` Ivan Gotovchits
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox