* [Caml-list] Phantom types and variants
@ 2014-08-22 3:11 Daniel Bünzli
2014-08-22 3:17 ` Daniel Bünzli
0 siblings, 1 reply; 6+ messages in thread
From: Daniel Bünzli @ 2014-08-22 3:11 UTC (permalink / raw)
To: Caml-list
Hello,
I'm pretty sure I have used the following pattern in the past. But the `coerce` function doesn't type. It's quite strange since the type variable is a phantom type so it should not enforce anything. Any hints ?
--------
module M : sig
type kind = [ `A | `B ]
type +'a t constraint 'a = [< kind ]
val a : unit -> [> `A] t
val b : unit -> [> `B] t
val coerce : ([> kind] as 'a) -> 'b t -> 'a t
end = struct
type kind = [ `A | `B ]
type +'a t =
{ kind : kind }
constraint 'a = [< kind]
let a () = { kind = `A }
let b () = { kind = `B }
let coerce k v = if v.kind <> k then invalid_arg "" else v
end
let (vl : [`A | `B ] M.t list) = [M.a (); M.b ()]
let (v : [`A] M.t) = M.coerce `A (List.hd vl)
--------
Fails with:
Values do not match:
val coerce : kind -> ([< kind ] as 'a) t -> 'a t
is not included in
val coerce : kind -> [< kind ] t -> kind t
Best,
Daniel
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [Caml-list] Phantom types and variants
2014-08-22 3:11 [Caml-list] Phantom types and variants Daniel Bünzli
@ 2014-08-22 3:17 ` Daniel Bünzli
2014-08-22 19:49 ` Philippe Veber
2014-08-23 15:40 ` Jeremy Yallop
0 siblings, 2 replies; 6+ messages in thread
From: Daniel Bünzli @ 2014-08-22 3:17 UTC (permalink / raw)
To: Caml-list
Sorry the coerce function type was wrong in my preceding message. Here is the example:
-----
module M : sig
type kind = [ `A | `B ]
type +'a t constraint 'a = [< kind ]
val a : unit -> [> `A] t
val b : unit -> [> `B] t
val coerce : ([< kind] as 'a) -> 'b t -> 'a t
end = struct
type kind = [ `A | `B ]
type +'a t =
{ kind : kind }
constraint 'a = [< kind]
let a () = { kind = `A }
let b () = { kind = `B }
let coerce k v = if v.kind <> k then invalid_arg "" else v
end
let (vl : [`A | `B ] M.t list) = [M.a (); M.b ()]
let (v : [`A] M.t) = M.coerce `A (List.hd vl)
------
and the error:
Values do not match:
val coerce : kind -> ([< kind ] as 'a) t -> 'a t
is not included in
val coerce : ([< kind ] as 'a) -> [< kind ] t -> 'a t
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [Caml-list] Phantom types and variants
2014-08-22 3:17 ` Daniel Bünzli
@ 2014-08-22 19:49 ` Philippe Veber
2014-08-23 15:06 ` Daniel Bünzli
2014-08-23 15:40 ` Jeremy Yallop
1 sibling, 1 reply; 6+ messages in thread
From: Philippe Veber @ 2014-08-22 19:49 UTC (permalink / raw)
To: Daniel Bünzli; +Cc: Caml-list
[-- Attachment #1: Type: text/plain, Size: 2374 bytes --]
Hi Daniel,
I really don't see how this could work, since with the definition of coerce:
let coerce k v = if v.kind <> k then invalid_arg "" else v
the expressions [v] and [coerce k v] must have the same type. So the type
of [coerce] necessarily is of the form [kind -> 'a t -> 'a t]. You'd have
to return a [t] made from [k] instead to capture its type. Here is another
proposal:
module M : sig
type kind = [ `A | `B ]
type +'a t constraint 'a = [< kind]
val a : unit -> [> `A] t
val b : unit -> [> `B] t
val coerce : ([< kind] as 'a) -> [< kind] t -> 'a t
end = struct
type kind = [ `A | `B ]
type +'a t =
{ kind : 'a } constraint 'a = [< kind]
let a () = { kind = `A }
let b () = { kind = `B }
let eq x y = match x, y with `A, `A | `B, `B -> true | `A, `B | `B, `A ->
false
let coerce k v = if eq v.kind k then invalid_arg "" else { v with kind =
k }
end
Not sure though, that this can be used in practice because of the [eq]
function: you can't write it with a catch-all case otherwise it does not
type with [< ... ] types as its domains. Maybe using GADTs here would be
more appropriate?
Cheers,
Philippe.
2014-08-22 5:17 GMT+02:00 Daniel Bünzli <daniel.buenzli@erratique.ch>:
> Sorry the coerce function type was wrong in my preceding message. Here is
> the example:
>
> -----
> module M : sig
> type kind = [ `A | `B ]
> type +'a t constraint 'a = [< kind ]
>
> val a : unit -> [> `A] t
> val b : unit -> [> `B] t
> val coerce : ([< kind] as 'a) -> 'b t -> 'a t
> end = struct
> type kind = [ `A | `B ]
> type +'a t =
> { kind : kind }
> constraint 'a = [< kind]
>
> let a () = { kind = `A }
> let b () = { kind = `B }
> let coerce k v = if v.kind <> k then invalid_arg "" else v
> end
>
> let (vl : [`A | `B ] M.t list) = [M.a (); M.b ()]
> let (v : [`A] M.t) = M.coerce `A (List.hd vl)
>
> ------
>
> and the error:
>
> Values do not match:
> val coerce : kind -> ([< kind ] as 'a) t -> 'a t
> is not included in
> val coerce : ([< kind ] as 'a) -> [< kind ] t -> 'a t
>
>
>
>
>
> --
> 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
>
[-- Attachment #2: Type: text/html, Size: 3571 bytes --]
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [Caml-list] Phantom types and variants
2014-08-22 19:49 ` Philippe Veber
@ 2014-08-23 15:06 ` Daniel Bünzli
0 siblings, 0 replies; 6+ messages in thread
From: Daniel Bünzli @ 2014-08-23 15:06 UTC (permalink / raw)
To: Philippe Veber; +Cc: Caml-list, Pierre Chambart
Le vendredi, 22 août 2014 à 20:49, Philippe Veber a écrit :
> Here is another proposal:
Thanks Philippe. I also thought about this solution but I wanted to avoid the new allocation. Note that you can actually write that solution without having to write that eq function. This makes the trick:
let coerce kind v = match kind with
| kind when (kind :> kind) = (v.kind :> kind) -> { v with kind = kind }
| _ -> invalid_arg ""
Pierre Chambart also responded to me privately (thanks), suggesting that I do not try to use variants themselves as the coercion specification but another more structured value. His solution (at the end of this email) works. But since I'm a little bit stubborn and that I would really like to use the variant for the coercion specification I tried to adapt its solution as follows. But it fails with a type error that I fail to understand:
Error: This definition has type ([< kind ] as 'a) -> 'a t
which is less general than 'b. ([< kind ] as 'b) -> 'b t
-------------
module M : sig
type kind = [ `A | `B ]
type +'a t constraint 'a = [< kind ]
val a : unit -> [> `A] t
val b : unit -> [> `B] t
val coerce : ([< kind] as 'a) -> 'b t -> 'a t
end = struct
type kind = [ `A | `B ]
type +'a t =
{ kind : kind;
coerce : 'b. ([< kind] as 'b) -> 'b t }
constraint 'a = [< kind ]
let a () =
let rec v = { kind = `A; coerce }
and coerce : 'b. ([< kind] as 'b) -> 'b t = function
| `A -> v | `B -> invalid_arg ""
in
v
let b () =
let rec v = { kind = `B; coerce }
and coerce : 'b. ([< kind] as 'b) ->'b t = function
| `A -> v | `B -> invalid_arg ""
in
v
let coerce kind v = v.coerce kind
end
-----------
Any hints ?
Best,
Daniel
Pierre Chambart's solution:
module M : sig
type kind = [ `A | `B ]
type +'a t constraint 'a = [< kind ]
type 'a coercer constraint 'a = [< kind]
val a : unit -> [> `A] t
val b : unit -> [> `B] t
val ac : [`A] coercer
val coerce : 'a coercer -> 'b t -> 'a t
end = struct
type kind = [ `A | `B ]
type +'a t =
{ kind : kind }
constraint 'a = [< kind]
type 'a coercer =
{ f : 'b. 'b t -> 'a t option }
constraint 'a = [< kind]
let a () = { kind = `A }
let b () = { kind = `B }
let ac = { f = (function ({ kind = `A } as v) -> Some v
| _ -> None) }
let coerce k v =
match k.f v with
| None -> invalid_arg ""
| Some v -> v
end
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [Caml-list] Phantom types and variants
2014-08-22 3:17 ` Daniel Bünzli
2014-08-22 19:49 ` Philippe Veber
@ 2014-08-23 15:40 ` Jeremy Yallop
2014-08-23 15:48 ` Daniel Bünzli
1 sibling, 1 reply; 6+ messages in thread
From: Jeremy Yallop @ 2014-08-23 15:40 UTC (permalink / raw)
To: Daniel Bünzli; +Cc: Caml-list
On 22 August 2014 04:17, Daniel Bünzli <daniel.buenzli@erratique.ch> wrote:
> Sorry the coerce function type was wrong in my preceding message. Here is the example:
>
> -----
> module M : sig
> type kind = [ `A | `B ]
> type +'a t constraint 'a = [< kind ]
>
> val a : unit -> [> `A] t
> val b : unit -> [> `B] t
> val coerce : ([< kind] as 'a) -> 'b t -> 'a t
> end = struct
> type kind = [ `A | `B ]
> type +'a t =
> { kind : kind }
> constraint 'a = [< kind]
>
> let a () = { kind = `A }
> let b () = { kind = `B }
> let coerce k v = if v.kind <> k then invalid_arg "" else v
> end
The following definition does the trick (and avoids the allocation):
let coerce (#kind as k) ({kind} as v) = if v.kind <> k then
invalid_arg "" else v
^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: [Caml-list] Phantom types and variants
2014-08-23 15:40 ` Jeremy Yallop
@ 2014-08-23 15:48 ` Daniel Bünzli
0 siblings, 0 replies; 6+ messages in thread
From: Daniel Bünzli @ 2014-08-23 15:48 UTC (permalink / raw)
To: Jeremy Yallop; +Cc: Caml-list
Le samedi, 23 août 2014 à 16:40, Jeremy Yallop a écrit :
> let coerce (#kind as k) ({kind} as v) = if v.kind <> k then
> invalid_arg "" else v
Wonderful. Thanks !
Daniel
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2014-08-23 15:49 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2014-08-22 3:11 [Caml-list] Phantom types and variants Daniel Bünzli
2014-08-22 3:17 ` Daniel Bünzli
2014-08-22 19:49 ` Philippe Veber
2014-08-23 15:06 ` Daniel Bünzli
2014-08-23 15:40 ` Jeremy Yallop
2014-08-23 15:48 ` Daniel Bünzli
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox