caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
From: Gabriel Scherer <gabriel.scherer@gmail.com>
To: "Milan Stanojević" <milanst@gmail.com>
Cc: Caml List <caml-list@inria.fr>
Subject: Re: [Caml-list] avoiding boilerplate with phantom types
Date: Sat, 10 Nov 2012 08:49:17 +0100	[thread overview]
Message-ID: <CAPFanBFQK2phsCgjtHXPCdmJ3SxpB=mCBcMz7cjhBPdnrpmuSw@mail.gmail.com> (raw)
In-Reply-To: <CAKR7PS_s1ENqr2i5b1Kc29m4g3i4ifyKmJrQmK=vEEzE0zJsAg@mail.gmail.com>

That doesn't directly answer your question, but nowadays with GADTs it
is possible to start first from the richly typed declaration (what
corresponds to your "phantom type" one, but replaced by real type
checks instead of hopeful signature coercion), and define the one
without this type information as an existential wrapper on top of it.

(* rich statically typed module *)
module B = struct
  type 'a t =
    | Unit : unit t
    | Int : int -> int t
    | Bool : bool -> bool t

  let foo : type a . a t -> int option = function
    | Int n -> Some n
    | _ -> None

  let bar : type a . a t -> bool option = function
    | Bool b -> Some b
    | _ -> None

  let baz n = Int n
end

(* dynamic interface without static type knowledge *)
module A = struct
  type a = Ex : 'a B.t -> a
  let foo (Ex b) = B.foo b
  let bar (Ex b) = B.bar b
  let baz n = Ex (B.baz n)
end

If I was to do something like this, I wouldn't directly reproduce the
module A with the same interface as B, but rather just wait in the
user code for a need to pack or unpack (foo B.t) into a, and do it
there -- so A is merely an example of doing that. The upside of this
is that it translates your intention without requesting duplication.
The downside is that GADT type checks are more complex than just usual
algebraic types (with or without phantom types) and the quality of
error messages is still pretty experimental.

So, not necessarily the right choice right now (but if you're moving
into phantom types you're somehow already asking for trouble), but
something to think about.

On Sat, Nov 10, 2012 at 1:02 AM, Milan Stanojević <milanst@gmail.com> wrote:
> This is my use case.
> I have a module A with type t and bunch of functions. I want to create
> module B which is just a wrapper around A with a phantom type
> Roughly
> module A : sig
>   type t
>   val foo : t -> int
>   val bar : t -> string
> end
>
> module B : sig
>    type phantom1
>    type phantom2
>    type 'a t   (* or maybe even type 'a t = private A.t *)
>    val foo : _ t -> int
>    val bar : _ t -> string
>
>    val validate : phantom1 t -> phantom2 t
> end
>
> I was hoping I can avoid copy-pasting declarations and that I can have
> some easy way to have A and B in sync as I add or remove functions
> from A.
> I was able to do something for implementation B but not for interface.
>
> B.ml
> type this_name_is_not_in_scope = A.t
> include (A : module type of A with type t = this_name_is_not_in_scope)
>
> type 'a t = A.t
> type phantom1
> type phantom2
> let validate = ....
>
> But for interface I can't do anything unless I expose type equality
> between 'a B.t and A.t (which renders phantom types useless) so I had
> to list all the functions by hand.
> Does anyone have a better way to do this?
>
> The problem is that I can't say include module type of A with type t := 'a t
> Why is this disallowed?
>
> Thanks,
>    Milan
>
> --
> 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

      reply	other threads:[~2012-11-10  7:49 UTC|newest]

Thread overview: 2+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2012-11-10  0:02 Milan Stanojević
2012-11-10  7:49 ` Gabriel Scherer [this message]

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='CAPFanBFQK2phsCgjtHXPCdmJ3SxpB=mCBcMz7cjhBPdnrpmuSw@mail.gmail.com' \
    --to=gabriel.scherer@gmail.com \
    --cc=caml-list@inria.fr \
    --cc=milanst@gmail.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).