From: Mikhail Mandrykin <mandrykin@ispras.ru>
To: caml-list@inria.fr, Spiros Eliopoulos <seliopou@gmail.com>
Cc: Jeremy Yallop <yallop@gmail.com>
Subject: Re: [Caml-list] "map"-ing parameterized class types
Date: Tue, 20 Oct 2015 14:57:56 +0300 [thread overview]
Message-ID: <2885279.d7QpSRfKLJ@molnar> (raw)
In-Reply-To: <CAEkQQgJNZ=yO8FugpgJpZE132WE6ZNnabx5jOKn5_0NZT8V8zQ@mail.gmail.com>
On Monday, October 19, 2015 04:15:54 PM Spiros Eliopoulos wrote:
> 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.
It seems this is essentially not the workaround that was pointed out, as the
suggestion was:
>> One approach is to
> > arrange things so that the recursion passes through a *non-structural
> > type*, such as a variant or record.
And an object type 'a container2 is a structural type. As far as I understand,
the semantics for type-checking of structural type abbreviations is the same
as if all those abbreviations were expanded. So introducing a new class ['a]
container2 doesn't help, because its corresponding object type ends up being
expanded while type-checking ['a] container1 anyway and leads to essentially
the same error. The regularity restriction seems to also arise from the same
expansion semantics where we would need to infinitely expand the structural
type abbreviation while checking itself and therefore would be unable to write
recursive structural types altogether, but the issue is addressed by replacing
the whole abbreviated type application with a type variable e.g. 'a container1
= 'self and using this 'self in place of all regular self-references. Thus the
type can remain structural (it's still possible to write it down without
naming it) despite the self-references e.g. ( < get : 'a; map : 'self > as
'self). For irregular self-references this doesn't work (if 'a container =
'self then what's 'b container or how to designate it to avoid infinite
expansion?).
Just in case an another possible work-around would be to use an abstract type
instead of a concrete nominal type as a proxy. This can be a little bit more
suitable as an abstract type can be later bound to the same structural type
and wrapping/unwrapping would become identity in the implementation. This is
more heavyweight, though, e.g:
module type S = sig
type 'a c'
val new_c : 'a -> 'a c'
end
module rec F' :
functor (M : S) -> sig
class ['a] c : 'a -> object
method get : 'a
method map : 'b. ('a -> 'b) -> 'b M.c'
end
end =
functor (M : S) -> struct
class ['a] c (a : 'a) = object
method get = a
method map : 'b. (_ -> 'b) -> 'b M.c' = fun f -> M.new_c (f a)
end
end
module rec F : sig
type 'a c'
class ['a] c : 'a -> object
method get : 'a
method map : 'b. ('a -> 'b) -> 'b F.c'
end
val new_c : 'a -> 'a F.c'
val self_cast : 'a c' -> 'a c
end = struct
module F' = F'(F)
class ['a] c = ['a] F'.c
type 'a c' = 'a c
let new_c a = new F.c a
let self_cast (x : 'a c') = (x : 'a c)
end
let () =
let c1 = new F.c 1 in
Printf.eprintf "%d\n" c1#get;
let c2 = F.self_cast @@ c1#map (string_of_int) in
Printf.eprintf "%s\n" c2#get
Here F.self_cast is actually an identity function an is only used to help
type-checking.
--
Mikhail Mandrykin
Linux Verification Center, ISPRAS
web: http://linuxtesting.org
e-mail: mandrykin@ispras.ru
next prev parent reply other threads:[~2015-10-20 11:58 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
2015-10-20 11:57 ` Mikhail Mandrykin [this message]
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=2885279.d7QpSRfKLJ@molnar \
--to=mandrykin@ispras.ru \
--cc=caml-list@inria.fr \
--cc=seliopou@gmail.com \
--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