caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
* Closed variants, type constraints and module signature
@ 2010-05-14 15:17 Philippe Veber
  2010-05-14 15:49 ` [Caml-list] " Jacques Garrigue
  0 siblings, 1 reply; 6+ messages in thread
From: Philippe Veber @ 2010-05-14 15:17 UTC (permalink / raw)
  To: caml-list

[-- Attachment #1: Type: text/plain, Size: 944 bytes --]

I'd like to define a type with a variable that is constrained to accept only
polymorphic variant types included in a given set of tags. That is how I
believed one should do :

        Objective Caml version 3.11.2

# type 'a t = 'a constraint 'a = [< `a | `b ];;
type 'a t = 'a constraint 'a = [< `a | `b ]


But I stumbled upon the following problem, when trying to use this
definition


# module type S = sig
  val v : 'a t
end;;
module type S = sig val v : [< `a | `b ] t end

# module I : S = struct
    let v = `a
  end;;

  Error: Signature mismatch:
       Modules do not match: sig val v : [> `a ] end is not included in S
       Values do not match:
         val v : [> `a ]
       is not included in
         val v : [< `a | `b ] t

Does anyone know why the definition of module I is rejected ? And if this is
the intended behavior, why does the following work ?

# let v : 'a t = `a
  ;;
val v : [< `a | `b > `a ] t = `a


Philippe.

[-- Attachment #2: Type: text/html, Size: 1482 bytes --]

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [Caml-list] Closed variants, type constraints and module signature
  2010-05-14 15:17 Closed variants, type constraints and module signature Philippe Veber
@ 2010-05-14 15:49 ` Jacques Garrigue
  2010-05-14 21:33   ` Philippe Veber
  0 siblings, 1 reply; 6+ messages in thread
From: Jacques Garrigue @ 2010-05-14 15:49 UTC (permalink / raw)
  To: philippe.veber; +Cc: caml-list

From: Philippe Veber <philippe.veber@googlemail.com>

> I'd like to define a type with a variable that is constrained to accept only
> polymorphic variant types included in a given set of tags. That is how I
> believed one should do :
> 
>         Objective Caml version 3.11.2
> 
> # type 'a t = 'a constraint 'a = [< `a | `b ];;
> type 'a t = 'a constraint 'a = [< `a | `b ]
>
> But I stumbled upon the following problem, when trying to use this
> definition
> 
> 
> # module type S = sig
>   val v : 'a t
> end;;
> module type S = sig val v : [< `a | `b ] t end
> 
> # module I : S = struct
>     let v = `a
>   end;;
> 
>   Error: Signature mismatch:
>        Modules do not match: sig val v : [> `a ] end is not included in S
>        Values do not match:
>          val v : [> `a ]
>        is not included in
>          val v : [< `a | `b ] t
> 
> Does anyone know why the definition of module I is rejected ? And if this is
> the intended behavior, why does the following work ?
> 
> # let v : 'a t = `a
>   ;;
> val v : [< `a | `b > `a ] t = `a

But it doesn't really work!
More precisely, the type [< `a | `b > `a ] t is an instance of 'a t,
not 'a t itself, an a module interface should give a type at most as
general as the implementation.

In your case, you should simply write

  type t = [`a | `b]

since you don't know what v may be.

Jacques Garrigue


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [Caml-list] Closed variants, type constraints and module  signature
  2010-05-14 15:49 ` [Caml-list] " Jacques Garrigue
@ 2010-05-14 21:33   ` Philippe Veber
  2010-05-15  0:54     ` Jacques Garrigue
  0 siblings, 1 reply; 6+ messages in thread
From: Philippe Veber @ 2010-05-14 21:33 UTC (permalink / raw)
  To: Jacques Garrigue; +Cc: caml-list

[-- Attachment #1: Type: text/plain, Size: 2414 bytes --]

2010/5/14 Jacques Garrigue <garrigue@math.nagoya-u.ac.jp>

> From: Philippe Veber <philippe.veber@googlemail.com>
>
> > I'd like to define a type with a variable that is constrained to accept
> only
> > polymorphic variant types included in a given set of tags. That is how I
> > believed one should do :
> >
> >         Objective Caml version 3.11.2
> >
> > # type 'a t = 'a constraint 'a = [< `a | `b ];;
> > type 'a t = 'a constraint 'a = [< `a | `b ]
> >
> > But I stumbled upon the following problem, when trying to use this
> > definition
> >
> >
> > # module type S = sig
> >   val v : 'a t
> > end;;
> > module type S = sig val v : [< `a | `b ] t end
> >
> > # module I : S = struct
> >     let v = `a
> >   end;;
> >
> >   Error: Signature mismatch:
> >        Modules do not match: sig val v : [> `a ] end is not included in S
> >        Values do not match:
> >          val v : [> `a ]
> >        is not included in
> >          val v : [< `a | `b ] t
> >
> > Does anyone know why the definition of module I is rejected ? And if this
> is
> > the intended behavior, why does the following work ?
> >
> > # let v : 'a t = `a
> >   ;;
> > val v : [< `a | `b > `a ] t = `a
>
> But it doesn't really work!
> More precisely, the type [< `a | `b > `a ] t is an instance of 'a t,
> not 'a t itself, an a module interface should give a type at most as
> general as the implementation.
>

Right, I understand now there are two different mechanisms at hand here : in
the module case, the type annotation for v is a specification, in the let
binding case, it is a constraint. Seems like my question was better suited
to beginners list ! Just to be sure : module I is rejected because v should
have type 'a t for all 'a satisfying the constraint 'a = [< `a | `b ], that
contain in particular [ `b ], which is incompatible with the type of v. Is
that correct ?



>
> In your case, you should simply write
>
>  type t = [`a | `b]
>
> since you don't know what v may be.
>

If i absolutely wanted to forbid other tags than `a and `b, while keeping
the possibility to manage subtype hierarchies, maybe I could also change the
code this way :

type u = [`a | `b]
type 'a t = 'a constraint 'a = [< u ]

module type S = sig
  val v : u t
  val f : 'a t -> [`a] t
end

module I : S = struct
  let v = `a
  let f _ = v
end

At least now the interpreter doesn't complain. Many thanks !

Philippe.



>
> Jacques Garrigue
>

[-- Attachment #2: Type: text/html, Size: 3619 bytes --]

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [Caml-list] Closed variants, type constraints and module signature
  2010-05-14 21:33   ` Philippe Veber
@ 2010-05-15  0:54     ` Jacques Garrigue
  2010-05-17 11:56       ` Philippe Veber
  0 siblings, 1 reply; 6+ messages in thread
From: Jacques Garrigue @ 2010-05-15  0:54 UTC (permalink / raw)
  To: philippe.veber; +Cc: caml-list

From: Philippe Veber <philippe.veber@googlemail.com>
> 2010/5/14 Jacques Garrigue <garrigue@math.nagoya-u.ac.jp>
> 
>> From: Philippe Veber <philippe.veber@googlemail.com>
>>
>> > I'd like to define a type with a variable that is constrained to accept
>> only
>> > polymorphic variant types included in a given set of tags. That is how I
>> > believed one should do :
...
>> > Does anyone know why the definition of module I is rejected ? And if this
>> is
>> > the intended behavior, why does the following work ?
>> >
>> > # let v : 'a t = `a
>> >   ;;
>> > val v : [< `a | `b > `a ] t = `a
>>
>> But it doesn't really work!
>> More precisely, the type [< `a | `b > `a ] t is an instance of 'a t,
>> not 'a t itself, an a module interface should give a type at most as
>> general as the implementation.
>>
> 
> Right, I understand now there are two different mechanisms at hand here : in
> the module case, the type annotation for v is a specification, in the let
> binding case, it is a constraint. Seems like my question was better suited
> to beginners list ! Just to be sure : module I is rejected because v should
> have type 'a t for all 'a satisfying the constraint 'a = [< `a | `b ], that
> contain in particular [ `b ], which is incompatible with the type of v. Is
> that correct ?

Yes, this is exactly the point I was trying to make. But it was a good
idea to post it here: this is a rather technical point, I don't read
the beginner-list usually, and your explanation is probably better
than mine.

>> In your case, you should simply write
>>
>>  type t = [`a | `b]
>>
>> since you don't know what v may be.
>>
> 
> If i absolutely wanted to forbid other tags than `a and `b, while keeping
> the possibility to manage subtype hierarchies, maybe I could also change the
> code this way :
> 
> type u = [`a | `b]
> type 'a t = 'a constraint 'a = [< u ]
> 
> module type S = sig
>   val v : u t
>   val f : 'a t -> [`a] t
> end
> 
> module I : S = struct
>   let v = `a
>   let f _ = v
> end
> 
> At least now the interpreter doesn't complain. Many thanks !

This indeed works, but I'm not sure of why you insist on defining a
constrained type. What is wrong with writing directly the following?

module type S = sig
  val v : u
  val f : [< u] -> [`a]
end

Constrained types have their uses, but I find them often confusing as
the type variable you write is not really a type variable.
Question of taste.

Jacques Garrigue


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [Caml-list] Closed variants, type constraints and module  signature
  2010-05-15  0:54     ` Jacques Garrigue
@ 2010-05-17 11:56       ` Philippe Veber
  2010-05-17 14:31         ` Jacques Garrigue
  0 siblings, 1 reply; 6+ messages in thread
From: Philippe Veber @ 2010-05-17 11:56 UTC (permalink / raw)
  To: Jacques Garrigue; +Cc: caml-list

[-- Attachment #1: Type: text/plain, Size: 3536 bytes --]

2010/5/15 Jacques Garrigue <garrigue@math.nagoya-u.ac.jp>

> From: Philippe Veber <philippe.veber@googlemail.com>
> > 2010/5/14 Jacques Garrigue <garrigue@math.nagoya-u.ac.jp>
> >
> >> From: Philippe Veber <philippe.veber@googlemail.com>
> >>
> >> > I'd like to define a type with a variable that is constrained to
> accept
> >> only
> >> > polymorphic variant types included in a given set of tags. That is how
> I
> >> > believed one should do :
> ...
> >> > Does anyone know why the definition of module I is rejected ? And if
> this
> >> is
> >> > the intended behavior, why does the following work ?
> >> >
> >> > # let v : 'a t = `a
> >> >   ;;
> >> > val v : [< `a | `b > `a ] t = `a
> >>
> >> But it doesn't really work!
> >> More precisely, the type [< `a | `b > `a ] t is an instance of 'a t,
> >> not 'a t itself, an a module interface should give a type at most as
> >> general as the implementation.
> >>
> >
> > Right, I understand now there are two different mechanisms at hand here :
> in
> > the module case, the type annotation for v is a specification, in the let
> > binding case, it is a constraint. Seems like my question was better
> suited
> > to beginners list ! Just to be sure : module I is rejected because v
> should
> > have type 'a t for all 'a satisfying the constraint 'a = [< `a | `b ],
> that
> > contain in particular [ `b ], which is incompatible with the type of v.
> Is
> > that correct ?
>
> Yes, this is exactly the point I was trying to make. But it was a good
> idea to post it here: this is a rather technical point, I don't read
> the beginner-list usually, and your explanation is probably better
> than mine.
>
> >> In your case, you should simply write
> >>
> >>  type t = [`a | `b]
> >>
> >> since you don't know what v may be.
> >>
> >
> > If i absolutely wanted to forbid other tags than `a and `b, while keeping
> > the possibility to manage subtype hierarchies, maybe I could also change
> the
> > code this way :
> >
> > type u = [`a | `b]
> > type 'a t = 'a constraint 'a = [< u ]
> >
> > module type S = sig
> >   val v : u t
> >   val f : 'a t -> [`a] t
> > end
> >
> > module I : S = struct
> >   let v = `a
> >   let f _ = v
> > end
> >
> > At least now the interpreter doesn't complain. Many thanks !
>
> This indeed works, but I'm not sure of why you insist on defining a
> constrained type. What is wrong with writing directly the following?
>
> module type S = sig
>  val v : u
>   val f : [< u] -> [`a]
> end
>
Well, nothing ! I'm affraid I chose an inappropriate solution to an
irrelevant problem. Initially i just wanted to be sure my polymorphic type
'a t would not be used with funny tags in 'a (I mean tags that have nothing
to do with t). But after all, there is (in my case) no rationale for this.
Second, types may be shorter to write :

val f : 'a t -> int

instead of

val f : [< u] t -> int

or

val f : [< My_type.u ] My_type.t -> int

if in another module. Well, now it's clearer for me it was not such a smart
idea. Your proposal is simpler and more natural.



> Constrained types have their uses,

which are, in brief ? Now I can't see a typical use for closed polymorphic
variant types (I mean types of the form 'a t constraint 'a = [< ... ])

but I find them often confusing as
> the type variable you write is not really a type variable.
>
why isn't it the case ? Aren't they simply type variables restricted to a
finite number of types ?

Anyway, thanks a lot for commenting on my problem !

Philippe.






> Question of taste.
>
> Jacques Garrigue
>

[-- Attachment #2: Type: text/html, Size: 5272 bytes --]

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [Caml-list] Closed variants, type constraints and module signature
  2010-05-17 11:56       ` Philippe Veber
@ 2010-05-17 14:31         ` Jacques Garrigue
  0 siblings, 0 replies; 6+ messages in thread
From: Jacques Garrigue @ 2010-05-17 14:31 UTC (permalink / raw)
  To: philippe.veber; +Cc: caml-list

From: Philippe Veber <philippe.veber@googlemail.com>
>> Constrained types have their uses,
> 
> which are, in brief ? Now I can't see a typical use for closed polymorphic
> variant types (I mean types of the form 'a t constraint 'a = [< ... ])

A typical use would be for objects, particularly when representing
virtual types (see the advanced part of the tutorial, in the reference
manual).
Another application is to use a record notation for type variables:

  type 'r t = .... constraint 'r = < env:'env; loc:'loc; typ:'typ; .. >
 
This way you can share multiple type parameters at once, and even
allow transparent addition of new parameters. This was not the
original goal of constraints, but I find it handy.

I have no immediate example with polymorphic variants, but your
arguments about scalability are valid: in some cases, constraints
allow more compact types. But at a cost.

>> but I find them often confusing as
>> the type variable you write is not really a type variable.
>>
> why isn't it the case ? Aren't they simply type variables restricted to a
> finite number of types ?

Yes they are constrained type variables.
But the problem is that the constraint is left implicit.

For instance, if somewhere you have defined

  type 'a t constraint 'a = [< `a | `b]

and inside an interface you write

  val f : 'a t -> int

the real meaning is

  val f : [< `a | `b] t -> int

I.e., you are hiding something.

This is not the same thing as type abbreviations, because constraints
are applied from the outside, while abbreviations just have to be
expanded.

Jacques Garrigue


^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2010-05-17 14:31 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2010-05-14 15:17 Closed variants, type constraints and module signature Philippe Veber
2010-05-14 15:49 ` [Caml-list] " Jacques Garrigue
2010-05-14 21:33   ` Philippe Veber
2010-05-15  0:54     ` Jacques Garrigue
2010-05-17 11:56       ` Philippe Veber
2010-05-17 14:31         ` Jacques Garrigue

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).