caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
From: Jacques Garrigue <garrigue@math.nagoya-u.ac.jp>
To: darioteixeira@yahoo.com
Cc: caml-list@yquem.inria.fr
Subject: Re: [Caml-list] Private types in 3.11, again
Date: Wed, 21 Jan 2009 19:38:55 +0900 (JST)	[thread overview]
Message-ID: <20090121.193855.42791952.garrigue@math.nagoya-u.ac.jp> (raw)
In-Reply-To: <865755.99476.qm@web111508.mail.gq1.yahoo.com>

From: Dario Teixeira <darioteixeira@yahoo.com>
> I ditched the regular variants in favour of polymorphic variants, hoping
> the coercion trick described by Jacques Garrigue would help [1].  I've also
> simplified the formulation as much as possible.  Anyway, I'm still stuck
> with the same problem: while function 'sprint' works alright inside the
> Node module, its clone 'sprint2' fails to compile when placed outside.
> Is this a case where no amount of explicit annotations and coercions will
> work or am I missing something obvious?
> 
> Thanks in advance!
> Regards,
> Dario Teixeira
> 
> [1] http://groups.google.com/group/fa.caml/msg/855011402f1ca1b5
> 
> 
> module Node:
> sig
> 	type elem_t = [ `Text of string | `Bold of elem_t list ]
> 	type +'a t = private elem_t
> 
> 	val text: string -> [> `Basic ] t
> 	val bold: 'a t list -> [> `Complex ] t
> 	val sprint: 'a t -> string
> end =
> struct
> 	type elem_t = [ `Text of string | `Bold of elem_t list ]
> 	type +'a t = elem_t
> 
> 	let text str = `Text str
> 	let bold seq = `Bold seq
> 	let rec sprint = function
> 		| `Text str	-> Printf.sprintf "(Text %s)" str
> 		| `Bold seq	-> Printf.sprintf "(Bold %s)" (List.fold_left (^) "" (List.map sprint seq))
> end
> 
> 
> module Foobar:
> sig
> 	val sprint2: 'a Node.t -> string
> end =
> struct
> 	let rec sprint2 node = match (node : _ Node.t :> [> ]) with
> 		| `Text str	-> Printf.sprintf "(Text %s)" str
> 		| `Bold seq	-> Printf.sprintf "(Bold %s)" (List.fold_left (^) "" (List.map sprint2 (seq : _ Node.t list :> [>] list)))
> end

The problem is clear enough: the annotation in your recursive call to
sprint2 is inverted. It assumes that seq has type Node.t, while it is
Node.elem_t, and tries to convert it to a list of variants, which is
incompatible to the input to sprint2, which is Node.t (due to the
annotation on node.)
But you cannot just revert the annotation, since the subtyping only
goes in one direction.
The solution here is to split the definition in two steps:

module Foobar:
sig
  val sprint2: 'a Node.t -> string
end = struct
  let rec sprint2 = function
    | `Text str	-> Printf.sprintf "(Text %s)" str
    | `Bold seq	-> Printf.sprintf "(Bold %s)" (List.fold_left (^) "" (List.map sprint2 seq))
  let sprint2 node = sprint2 (node : 'a Node.t :> [> ])
end

However, I agree with my eponym that there is little point in using a
private abbreviation where you could use a private row, and avoid
coercions. When doing this, you have to be careful that your type is
recursive, so that the row should be recursive too.

You should change the signature to be:
  type 'a elem_t = [ `Text of string | `Bold of 'a list ]
  type +'a t = private [< 'b elem_t] as 'b
and the implementation
  type 'a elem_t = [ `Text of string | `Bold of 'a list ]
  type +'a t = 'b elem_t as 'b

Then the module Foobar types without any coercion.

I have also looked at your previous code, using normal variants.
It looks like you are trying to do something like GADTs, and I don't
see how you could possibly do that without adding some support inside
the first module (where the phantom type is defined.) For instance,
you could define a generic mapping function there, and use instances
of it outside of the module.

Hope this helps,

Jacques Garrigue 


  parent reply	other threads:[~2009-01-21 10:49 UTC|newest]

Thread overview: 13+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-01-15 17:31 Dario Teixeira
2009-01-19 15:09 ` [Caml-list] " Dario Teixeira
2009-01-20 16:33   ` Dario Teixeira
2009-01-20 17:29     ` Jacques Carette
2009-01-20 17:48       ` Dario Teixeira
2009-01-21 10:48       ` Jacques Garrigue
2009-01-21 10:38     ` Jacques Garrigue [this message]
2009-01-21 13:22   ` Jacques Garrigue
2009-01-21 19:11     ` Dario Teixeira
2009-01-21 20:17       ` Gabriel Kerneis
2009-01-21 21:52         ` GADTs in Ocaml (was: Private types in 3.11, again) Dario Teixeira
2009-01-22  1:36       ` [Caml-list] Private types in 3.11, again Jacques Garrigue
2009-01-26 15:13 Dario Teixeira

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20090121.193855.42791952.garrigue@math.nagoya-u.ac.jp \
    --to=garrigue@math.nagoya-u.ac.jp \
    --cc=caml-list@yquem.inria.fr \
    --cc=darioteixeira@yahoo.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
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).