caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
From: "Leo White" <leo@lpw25.net>
To: caml-list@inria.fr
Subject: Re: [Caml-list] Breaking type abstraction of modules
Date: Sat, 27 Feb 2021 11:37:27 +0000	[thread overview]
Message-ID: <de6adcbd-bd7b-45b9-9d1b-e8ff5a32a4f4@www.fastmail.com> (raw)
In-Reply-To: <20210227105013.GA2146@Melchior.localnet>

Hi Oleg,

I don't really understand your unease here. Firstly, this isn't some unexpected aspect of extensible variants, it is the main reason that I proposed adding them to the language. Secondly, you can easily create similar behaviour without extensible variants. For example, here we do the same thing without extensibility (code not actually tested or even type-checked):

type (_, _) eq = Refl : ('a, 'b) eq

module Rep : sig
  type 'a t
  val int : int t
  val string : string t
  val destruct : 'a t -> 'b t -> ('a, 'b) eq option
end = struct
  type 'a rep =
    | Int : int rep
    | String : int rep
  let int = Int
  let string = String
  let destruct (type a b) (a : a t) (b : b t) =
    match a, b with
    | Int, Int -> Some Refl
    | String, String -> Some Refl
    | _, _ -> None
end

let counter = ref 0
 
module AF() : sig
  type t             (* Here, t is abstract *)
  val rep : t Rep.t
  val x : t
end = struct
  type t = int        (* Here, t is concrete int *)
  let rep = Rep.int
  let x = incr counter; !counter
end

module A1 = AF ()
module A2 = AF ()

let ar = ref [A1.x]
 
let _ =
   match Rep.destruct A1.rep A2.rep with 
    | Some Refl -> ar := A2.x :: !ar
    | _ -> assert false

Extensible variants make these kinds of type representations much more useful, but they don't change the nature of what you can do.

Regards,

Leo

On Sat, 27 Feb 2021, at 10:50 AM, Oleg wrote:
> 
> Gabriel Scherer wrote:
> 
> > Is this very different from exposing the GADT equality directly in the
> > module interface?
> >
> > module A : sig
> >   type t (* abstract *)
> >   val reveals_abstraction : (int, t) eq (* or maybe not *)
> >   val x : t
> > end
> 
> I think it is different: if you are declaring reveals_abstraction
> (that is, the witness of the type equality) in your _interface_, you are
> effectively declaring to the users that "type t = int", no? 
> 
> Thinking about this more, I come across the following example that
> better illustrates my unease. The example concerns type generativity,
> and explicit promise by generative functors to create fresh,
> incompatible types. It seems this promise has to come with some
> conditions attached.
> 
> Assuming the same preamble with teq as before, consider the following
> code
> 
>   let counter = ref 0
> 
>   module AF() : sig
>     type t             (* Here, t is abstract *)
>     type _ trep += AT : t trep
>     val x : t
>    end = struct
>     type t = int        (* Here, t is concrete int *)
>     type _ trep += AT : t trep
>     let x = incr counter; !counter
> 
>     let () = 
>      let teq : type a b. a trep -> b trep -> (a,b) eq option = fun x y -> 
>        match (x,y) with 
>        | (AT,AT) -> Some Refl 
>        | (AT,Int) -> Some Refl      (* Since t = int, it type checks *)
>        | (Int,AT) -> Some Refl
>        | _ -> None 
>     in teq_extend {teq=teq}
>   end
> 
> Here, AF is a generative functor. The type t is defined
> abstract. Hence each instantiation of AF should come with its own,
> fresh and incompatible with anything else type t. (For the same of
> example below, the value x is also made fresh).
> 
> Here are the two instances of the functor.
> 
>    module A1 = AF ()
>    module A2 = AF ()
> 
> Indeed, the types A1.t and A2.t are different: putting A1.x and A2.x
> into the same list predictably fails.
> 
>    let _ = [A1.x; A2.x]
> 
> Line 1, characters 15-19:
> 1 | let _ = [A1.x; A2.x];;
>                    ^^^^
> Error: This expression has type A2.t but an expression was expected of type
>          A1.t
> 
> 
> But now it succeeds:
> 
>    let ar = ref [A1.x]
> 
>    let _ = match (teq A1.AT Int, teq A2.AT Int) with 
>             | (Some Refl,Some Refl) -> ar := A2.x :: !ar
>             | _ -> assert false
> 
>    let _ = !ar
> - : A1.t list = [<abstr>; <abstr>]
> 
> The list in ar really has A2.x and A1.x as elements, which we can confirm
> as
> 
>    let _ = match teq A1.AT Int with
>            | Some Refl -> (!ar : int list) 
>            | _ -> assert false
> 
> - : int list = [2; 1]
>

  reply	other threads:[~2021-02-27 11:37 UTC|newest]

Thread overview: 5+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2021-02-26 16:28 Oleg
2021-02-26 16:29 ` Gabriel Scherer
2021-02-27 10:50   ` Oleg
2021-02-27 11:37     ` Leo White [this message]
2021-03-02  8:08       ` [Caml-list] [ANN] latest batteries release: v3.3.0 Francois Berenger

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=de6adcbd-bd7b-45b9-9d1b-e8ff5a32a4f4@www.fastmail.com \
    --to=leo@lpw25.net \
    --cc=caml-list@inria.fr \
    /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).