caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
* [Caml-list] Constraining abstract type to be of a given subtype
@ 2011-02-21 15:56 Dario Teixeira
  2011-02-21 17:07 ` Guillaume Yziquel
  0 siblings, 1 reply; 10+ messages in thread
From: Dario Teixeira @ 2011-02-21 15:56 UTC (permalink / raw)
  To: caml-list

Hi,

In a signature FOO, I'm trying to constrain an abstract type kind_t to be a
subtype of Kind.t (please see code below).  However, I get a compiler error
when I declare an actual struct Foo1 which supposedly obeys signature FOO:

  Type declarations do not match:
    type 'a kind_t = [ `A ]
  is not included in
    type 'a kind_t = 'a constraint 'a = [< Kind.t ]


Any hints as to what is wrong here?  Thanks in advance for your help!

Best regards,
Dario Teixeira


module Kind:
sig
	type t = [ `A | `B | `C ]

	val to_string: t -> string
end =
struct
	type t = [ `A | `B | `C ]

	let to_string = function
		| `A -> "A"
		| `B -> "B"
		| `C -> "C"
end


module type FOO =
sig
	type custom_t
	type 'a kind_t = 'a constraint 'a = [< Kind.t ]
	type 'a t = int * custom_t * 'a kind_t

	val make: int -> custom_t -> 'a kind_t -> 'a t
	val string_of_custom: custom_t -> string
	val string_of_kind: 'a kind_t -> string
end


module Foo1: FOO =
struct
	type custom_t = float
	type 'a kind_t = [ `A ]
	type 'a t = int * custom_t * 'a kind_t

	let make id custom kind = (id, custom, kind)
	let string_of_custom = string_of_float
	let string_of_kind k = Kind.to_string (k :> Kind.t)
end



      


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

* Re: [Caml-list] Constraining abstract type to be of a given subtype
  2011-02-21 15:56 [Caml-list] Constraining abstract type to be of a given subtype Dario Teixeira
@ 2011-02-21 17:07 ` Guillaume Yziquel
  2011-02-21 18:42   ` Dario Teixeira
  0 siblings, 1 reply; 10+ messages in thread
From: Guillaume Yziquel @ 2011-02-21 17:07 UTC (permalink / raw)
  To: Dario Teixeira; +Cc: caml-list

Le Monday 21 Feb 2011 à 07:56:43 (-0800), Dario Teixeira a écrit :
> Hi,
> 
> In a signature FOO, I'm trying to constrain an abstract type kind_t to be a
> subtype of Kind.t (please see code below).  However, I get a compiler error
> when I declare an actual struct Foo1 which supposedly obeys signature FOO:
> 
>   Type declarations do not match:
>     type 'a kind_t = [ `A ]
>   is not included in
>     type 'a kind_t = 'a constraint 'a = [< Kind.t ]
> 
> 
> Any hints as to what is wrong here?  Thanks in advance for your help!

Well, I clearly see to what 'a is bound to in

	type 'a kind_t = 'a constraint 'a = [< Kind.t ]

but I do not see to what 'a is bound to in

	type 'a kind_t = [ `A ]

As 'a kind_t is declared to be 'a in the first type declaration, it
should also be the case in the second type declaration. However, 'a is a
phantom type parameter there.

> Best regards,
> Dario Teixeira

But I think that you will not be able to do such type narrowing in a
module interface / module interface fashion. At least not without an
indication of covariance or contravariance. And even then, I'm not sure
if that is possible.

-- 
     Guillaume Yziquel


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

* Re: [Caml-list] Constraining abstract type to be of a given subtype
  2011-02-21 17:07 ` Guillaume Yziquel
@ 2011-02-21 18:42   ` Dario Teixeira
  2011-02-21 19:26     ` Guillaume Yziquel
  2011-02-21 19:39     ` Daniel Bünzli
  0 siblings, 2 replies; 10+ messages in thread
From: Dario Teixeira @ 2011-02-21 18:42 UTC (permalink / raw)
  To: Guillaume Yziquel; +Cc: caml-list

Hi,

> But I think that you will not be able to do such type narrowing in a
> module interface / module interface fashion. At least not without an
> indication of covariance or contravariance. And even then, I'm not sure
> if that is possible.

Perhaps I am indeed pushing the module language beyond its design
intentions, but my requirement does not strike me as completely
unreasonable...

If I get rid of the constraint altogether, then I lose the guarantee that
kind_t is a subtype of Kind.t.  But if I declare kind_t = Kind.t in the
signature FOO, then I lose the ability to declare particular instances
of FOO to be more *tightly* constrained than the generic Kind.t.

Any further ideas on how I may be able to have my cake and eat it too?

Cheers,
Dario Teixeira



      


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

* Re: [Caml-list] Constraining abstract type to be of a given subtype
  2011-02-21 18:42   ` Dario Teixeira
@ 2011-02-21 19:26     ` Guillaume Yziquel
  2011-02-21 19:39     ` Daniel Bünzli
  1 sibling, 0 replies; 10+ messages in thread
From: Guillaume Yziquel @ 2011-02-21 19:26 UTC (permalink / raw)
  To: Dario Teixeira; +Cc: caml-list

Le Monday 21 Feb 2011 à 10:42:43 (-0800), Dario Teixeira a écrit :
> Hi,
> 
> > But I think that you will not be able to do such type narrowing in a
> > module interface / module interface fashion. At least not without an
> > indication of covariance or contravariance. And even then, I'm not sure
> > if that is possible.
> 
> Perhaps I am indeed pushing the module language beyond its design
> intentions, but my requirement does not strike me as completely
> unreasonable...
> 
> If I get rid of the constraint altogether, then I lose the guarantee that
> kind_t is a subtype of Kind.t.  But if I declare kind_t = Kind.t in the
> signature FOO, then I lose the ability to declare particular instances
> of FOO to be more *tightly* constrained than the generic Kind.t.
> 
> Any further ideas on how I may be able to have my cake and eat it too?
> 
> Cheers,
> Dario Teixeira

I think it's going to be tough. The closest I've come to is:

# module type Q = sig type 'a t end;;
module type Q = sig type 'a t end
# module type W = Q with type 'a t = [< `A | `B] as 'a;;
Error: In this `with' constraint, the new definition of t
       does not match its original definition in the constrained
signature:
       Type declarations do not match:
         type 'a t = 'a constraint 'a = [< `A | `B ]
       is not included in
         type 'a t
       Their constraints differ.

While it is possible to 'specialise' a type in a module type signature,
it seems unlikely that it is possible to 'specialise' constraints to
narrower constraints.


-- 
     Guillaume Yziquel


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

* Re: [Caml-list] Constraining abstract type to be of a given subtype
  2011-02-21 18:42   ` Dario Teixeira
  2011-02-21 19:26     ` Guillaume Yziquel
@ 2011-02-21 19:39     ` Daniel Bünzli
  2011-02-21 20:22       ` Dario Teixeira
  1 sibling, 1 reply; 10+ messages in thread
From: Daniel Bünzli @ 2011-02-21 19:39 UTC (permalink / raw)
  To: Dario Teixeira; +Cc: caml-list

I'm just wondering.

Abstraction is about hiding type representation. Variant subtyping is
a kind of structural subtyping and is thus about type representation.
So constraining an abstract type to be of a given structural subtype
seems contradictory.

The only way I see to type what you want is to make FOO.kind_t
abstract. This doesn't ensure that the implementation of 'a kind_t is
a subtype of Kind.t itself. However if your goal is some kind of
phantom type constraints, it will do the job. And you can still
require a function to convert 'a kind to Kind.t. See the code below.

Best,

Daniel


module Kind:
sig
       type t = [ `A | `B | `C ]

       val to_string: t -> string
end =
struct
       type t = [ `A | `B | `C ]

       let to_string = function
               | `A -> "A"
               | `B -> "B"
               | `C -> "C"
end

module type FOO =
sig
       type custom_t
       type 'a kind_t constraint 'a = [< Kind.t]
       type 'a t = int * custom_t * 'a kind_t

       val make: int -> custom_t -> 'a kind_t -> 'a t
       val string_of_custom: custom_t -> string
       val string_of_kind: 'a kind_t -> string
       val kind_to_kind : 'a kind_t -> Kind.t
end


module Foo1: FOO =
struct
       type custom_t = float
       type 'a kind_t = [`A] constraint 'a = [< Kind.t]
       type 'a t = int * custom_t * 'a kind_t

       let make id custom kind = (id, custom, kind)
       let string_of_custom = string_of_float
       let string_of_kind k = Kind.to_string (k :> Kind.t)
       let kind_to_kind k = (k :> Kind.t)
end

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

* Re: [Caml-list] Constraining abstract type to be of a given subtype
  2011-02-21 19:39     ` Daniel Bünzli
@ 2011-02-21 20:22       ` Dario Teixeira
  2011-02-21 20:59         ` Daniel Bünzli
  0 siblings, 1 reply; 10+ messages in thread
From: Dario Teixeira @ 2011-02-21 20:22 UTC (permalink / raw)
  To: Daniel Bünzli; +Cc: caml-list

Hi,

> Abstraction is about hiding type representation. Variant subtyping is
> a kind of structural subtyping and is thus about type representation.
> So constraining an abstract type to be of a given structural subtype
> seems contradictory.

Yes, you're right, I abused the term "abstract type", when I meant to
say that the type exposed by the interface was not your run-of-the-mill
concrete type but instead any type that satisfied a given constraint.
What would be the proper terminology in this case?


> The only way I see to type what you want is to make FOO.kind_t
> abstract. This doesn't ensure that the implementation of 'a kind_t is
> a subtype of Kind.t itself. However if your goal is some kind of
> phantom type constraints, it will do the job. And you can still
> require a function to convert 'a kind to Kind.t. See the code below.

Which does work quite nicely, thanks!

Cheers,
Dario



      


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

* Re: [Caml-list] Constraining abstract type to be of a given subtype
  2011-02-21 20:22       ` Dario Teixeira
@ 2011-02-21 20:59         ` Daniel Bünzli
  2011-02-21 21:31           ` Daniel Bünzli
  0 siblings, 1 reply; 10+ messages in thread
From: Daniel Bünzli @ 2011-02-21 20:59 UTC (permalink / raw)
  To: Dario Teixeira; +Cc: caml-list

> Which does work quite nicely, thanks!

In fact it does compile but I don't think it does what you want
because the 'a is completly unrelated to the `A in Foo1.kind_t

Daniel

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

* Re: [Caml-list] Constraining abstract type to be of a given subtype
  2011-02-21 20:59         ` Daniel Bünzli
@ 2011-02-21 21:31           ` Daniel Bünzli
  2011-02-21 21:49             ` Daniel Bünzli
  0 siblings, 1 reply; 10+ messages in thread
From: Daniel Bünzli @ 2011-02-21 21:31 UTC (permalink / raw)
  To: Dario Teixeira; +Cc: caml-list

> In fact it does compile but I don't think it does what you want
> because the 'a is completly unrelated to the `A in Foo1.kind_t

Oh well it's always the same error : when you are doing phantom types,
the type with phantoms should be abstract. See below.

Daniel

module Kind:
sig
      type t = [ `A | `B | `C ]

      val to_string: t -> string
end =
struct
      type t = [ `A | `B | `C ]

      let to_string = function
              | `A -> "A"
              | `B -> "B"
              | `C -> "C"
end

module type FOO =
sig
      type custom_t
      type 'a kind_t constraint 'a = [< Kind.t]
      type 'a t = int * custom_t * 'a kind_t

      val make: int -> custom_t -> 'a kind_t -> 'a t
      val string_of_custom: custom_t -> string
      val string_of_kind: 'a kind_t -> string
      val kind_to_kind : 'a kind_t -> Kind.t
end


module Foo1 : sig
      type custom_t
      type 'a kind_t constraint 'a = [< Kind.t]
      type 'a t = int * custom_t * 'a kind_t

      val make_custom : float -> custom_t
      val make: int -> custom_t -> 'a kind_t -> 'a t
      val string_of_custom: custom_t -> string
      val string_of_kind: 'a kind_t -> string
      val kind_of_kind : ([ `A ] as 'a) -> 'a kind_t
      val kind_to_kind : 'a kind_t -> Kind.t
end = struct
      type custom_t = float
      type 'a kind_t = [`A] constraint 'a = [< Kind.t]
      type 'a t = int * custom_t * 'a kind_t

      let make_custom f = f
      let make id custom kind = (id, custom, kind)
      let string_of_custom = string_of_float
      let string_of_kind k = Kind.to_string (k :> Kind.t)
      let kind_of_kind k = k
      let kind_to_kind k = (k :> Kind.t)
end

let (v : [`A] Foo1.t) =
  Foo1.make 2 (Foo1.make_custom 2.) (Foo1.kind_of_kind `A)

(* Should not typecheck
let (v : [`B] Foo1.t) =
  Foo1.make 2 (Foo1.make_custom 2.) (Foo1.kind_of_kind `A)
*)

module FOOCheck = (Foo1 : FOO)

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

* Re: [Caml-list] Constraining abstract type to be of a given subtype
  2011-02-21 21:31           ` Daniel Bünzli
@ 2011-02-21 21:49             ` Daniel Bünzli
  2011-02-22 16:15               ` Dario Teixeira
  0 siblings, 1 reply; 10+ messages in thread
From: Daniel Bünzli @ 2011-02-21 21:49 UTC (permalink / raw)
  To: Dario Teixeira; +Cc: caml-list

Ok last message I promise.

I don't know exactly what you want but you may prefer the following
FOO (see the signature of kind_to_kind)  :

module type FOO =
sig
      type custom_t
      type 'a kind_t constraint 'a = [< Kind.t]
      type 'a t = int * custom_t * 'a kind_t

      val make: int -> custom_t -> 'a kind_t -> 'a t
      val string_of_custom: custom_t -> string
      val string_of_kind: 'a kind_t -> string
      val kind_to_kind : 'a kind_t -> 'a
end

In that case the idea is that each implementer declares kind as :

type 'a kind = 'a constraint 'a = [< Kind.t]

but controls which 'a it will actually allow via the kind_of_kind
function (better names to be found)  :

module FooAB : sig
      type custom_t
      type 'a kind_t constraint 'a = [< Kind.t]
      type 'a t = int * custom_t * 'a kind_t

      val make_custom : float -> custom_t
      val make: int -> custom_t -> 'a kind_t -> 'a t
      val string_of_custom: custom_t -> string
      val string_of_kind: 'a kind_t -> string
      val kind_of_kind : ([ `A | `B] as 'a) -> 'a kind_t
      val kind_to_kind : 'a kind_t -> 'a
end = struct
      type custom_t = float
      type 'a kind_t = 'a constraint 'a = [< Kind.t]
      type 'a t = int * custom_t * 'a kind_t

      let make_custom f = f
      let make id custom kind = (id, custom, kind)
      let string_of_custom = string_of_float
      let string_of_kind k = Kind.to_string (k :> Kind.t)
      let kind_of_kind k = k
      let kind_to_kind k = k
end

let (v : [`A | `B] FooAB.t) =
  FooAB.make 2 (FooAB.make_custom 2.) (FooAB.kind_of_kind `A)

let (v : [`A | `B] FooAB.t) =
  FooAB.make 2 (FooAB.make_custom 2.) (FooAB.kind_of_kind `B)

let (k : [`A |`B]) = FooAB.kind_to_kind (FooAB.kind_of_kind `A)

(* Should not typecheck
 let v = FooAB.make 2 (FooAB.make_custom 2.) (FooAB.kind_of_kind `C) *)



module FOOCheck = (FooAB : FOO)

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

* Re: [Caml-list] Constraining abstract type to be of a given subtype
  2011-02-21 21:49             ` Daniel Bünzli
@ 2011-02-22 16:15               ` Dario Teixeira
  0 siblings, 0 replies; 10+ messages in thread
From: Dario Teixeira @ 2011-02-22 16:15 UTC (permalink / raw)
  To: Daniel Bünzli; +Cc: caml-list

Hi Daniel,

> Ok last message I promise.

No problem -- I appreciate the help, thanks!

> I don't know exactly what you want but you may prefer the following
> FOO (see the signature of kind_to_kind)  :

I decided to take a step back and forgo the constraint.  That is, I'm
making the type really abstract, even if in practice all the concrete
implementations of signature FOO will have a kind_t that is a subtype
of Kind.t.

Though it's nice to use the type system to ensure correctness by
construction, in situations (like this one) where one is pushing
against the limits of the type system, the solution can end up
being too cumbersome to use in practice.  Cf, per example, the
pre-3.13 type system tricks to encode GADTs that have been presented
in this list: though brilliant, they haven't gained that much
traction in actual usage because of the associated overhead.

Best regards,
Dario Teixeira



      


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

end of thread, other threads:[~2011-02-22 16:15 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-02-21 15:56 [Caml-list] Constraining abstract type to be of a given subtype Dario Teixeira
2011-02-21 17:07 ` Guillaume Yziquel
2011-02-21 18:42   ` Dario Teixeira
2011-02-21 19:26     ` Guillaume Yziquel
2011-02-21 19:39     ` Daniel Bünzli
2011-02-21 20:22       ` Dario Teixeira
2011-02-21 20:59         ` Daniel Bünzli
2011-02-21 21:31           ` Daniel Bünzli
2011-02-21 21:49             ` Daniel Bünzli
2011-02-22 16:15               ` Dario Teixeira

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