caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
From: Spiros Eliopoulos <seliopou@gmail.com>
To: Jeremy Yallop <yallop@gmail.com>
Cc: OCaml <caml-list@inria.fr>
Subject: Re: [Caml-list] "map"-ing parameterized class types
Date: Mon, 19 Oct 2015 16:15:54 -0400	[thread overview]
Message-ID: <CAEkQQgJNZ=yO8FugpgJpZE132WE6ZNnabx5jOKn5_0NZT8V8zQ@mail.gmail.com> (raw)
In-Reply-To: <CAAxsn=HhhmAAYfSCLzWgMW0Q-duTZNQBLQYDx8yETwWTjm16tw@mail.gmail.com>

[-- Attachment #1: Type: text/plain, Size: 5006 bytes --]

Thank, Jeremy, for the great explanation and possible work around.
Unfortunately for me, the workaround won't be possible to use for the
js_of_ocaml use case I have in mind. At least not without sprinkling
Obj.magic everywhere, which is what I'm trying to avoid.

Based on your workaround, I thought I might be able to create my own
workaround with code that looked something like this:

  module rec R : sig
    class type ['a] container1 = object
      method map : ('a -> 'b) -> 'b R.container2
    end
    class type ['a] container2 = object
      method op : 'a R.container1
    end
  end = struct
    ...
  end

But of course the type system complained that:

  Error: In the definition of R.container2, type
       'b R.container1
       should be
       'a R.container1

I thought this might be for a different than the one you mentioned, but
upon further reflection and a single unrolling of the types, it seems to be
the regular type constraint that's causing this error as well.

Well, back to drawing board. Thanks again.

On Mon, Oct 19, 2015 at 2:14 PM, Jeremy Yallop <yallop@gmail.com> wrote:

> On 19 October 2015 at 17:58, Spiros Eliopoulos <seliopou@gmail.com> wrote:
> > I'm trying to create a "container" class[0] that can store a value of
> type
> > 'a, and transform that value to another value of type 'b. I'm trying to
> do
> > this by including a "map" method in the container that applies a
> function to
> > the value and returns a new instance of container with the transformed
> > value. Despite the annotations, the types aren't working out as I
> expected:
> >
> >   class ['a] container (v:'a) = object
> >     method map (f:'a -> 'b) : 'b container = new container (f v)
> >   end;;
> >   (* class ['a] container : 'a -> object method map : ('a -> 'a) -> 'a
> > container end  *)
> >
> > I gather I'm either doing something wrong, or it's not possible. I
> suppose
> > my question, which one is it?
>
> It's not exactly possible, but there are workarounds.
>
> The reason the types don't work out as you expect is that structural
> types (objects, classes, polymorphic variants) in OCaml are required
> to be "regular".  A parameterised type t is regular if every
> occurrence of t within its own definition is instantiated with the
> parameters.  For example, the following type (t1) is regular:
>
>    # type ('a, 'b) t1 = [`A of ('a, 'b) t1];;
>    type ('a, 'b) t1 = [ `A of ('a, 'b) t1 ]
>      type ('a, 'b) t1 = [`A of ('a, 'b) t1]
>
> but this one (t2) isn't, because the order of parameters is reversed
>
>    # type ('a, 'b) t2 = [`A of ('b, 'a) t2];;
>    Characters 5-38:
>      type ('a, 'b) t2 = [`A of ('b, 'a) t2];;
>           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>    Error: In the definition of t2, type ('b, 'a) t2 should be ('a, 'b) t2
>      type ('a, 'b) t2 = [`A of ('b, 'a) t2]
>
> and this one (t3) isn't, either, because the parameters are
> instantiated with concrete types
>
>    # type ('a, 'b) t3 = [`A of (int, string) t3];;
>    Characters 5-43:
>      type ('a, 'b) t3 = [`A of (int, string) t3];;
>           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>    Error: In the definition of t3, type (int, string) t3 should be ('a,
> 'b) t3
>
> As the output shows, OCaml rejects the non-regular definitions for t2
> and t3.  Your example code also attempts to define a non-regular type,
> but since the type variable 'b is available for unification, OCaml
> doesn't need to reject the definition altogether.  Instead, 'b is
> unified with the class parameter 'a to produce a regular type which is
> acceptable to OCaml (but which doesn't do what you want).
>
> How might we side-step the regularity constraint?  One approach is to
> arrange things so that the recursion passes through a non-structural
> type, such as a variant or record.  In an imaginary extension to OCaml
> with support for groups of mutually-recursive types and classes we
> could write something like this:
>
>    class ['a] container (v:'a) = object
>      method map : 'b. ('a -> 'b) -> 'b container_aux =
>        fun f -> { container = new container (f v) }
>    end
>    and 'a container_aux = { container: 'a container }
>
> In today's OCaml we can achieve a similar effect by routing all the
> recursive references through a recursive module, albeit at a rather
> heavy syntactic cost:
>
>    module rec R:
>    sig
>      class ['a] container : 'a ->
>        object
>          method map : 'b. ('a -> 'b) -> 'b R.container_aux
>        end
>      type 'a container_aux = { container: 'a container }
>    end =
>    struct
>      class ['a] container (v:'a) = object
>        method map : 'b. ('a -> 'b) -> 'b R.container_aux =
>          fun f -> { R.container = new R.container (f v) }
>      end
>      type 'a container_aux = { container: 'a container }
>    end
>
> which at least achieves the desired effect:
>
>    # let c = new R.container 3;;
>    val c : int R.container = <obj>
>    # (c#map string_of_int).R.container;;
>    - : string R.container = <obj>
>

[-- Attachment #2: Type: text/html, Size: 6652 bytes --]

  reply	other threads:[~2015-10-19 20:16 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-10-19 16:58 Spiros Eliopoulos
2015-10-19 18:14 ` Jeremy Yallop
2015-10-19 20:15   ` Spiros Eliopoulos [this message]
2015-10-20 11:57     ` Mikhail Mandrykin
2015-11-26 23:25       ` Glen Mével
2015-10-22 15:04     ` Oleg
2015-10-23  6:48       ` Jacques Garrigue

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='CAEkQQgJNZ=yO8FugpgJpZE132WE6ZNnabx5jOKn5_0NZT8V8zQ@mail.gmail.com' \
    --to=seliopou@gmail.com \
    --cc=caml-list@inria.fr \
    --cc=yallop@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).