From: Goswin von Brederlow <goswin-v-b@web.de>
To: caml-list@inria.fr
Subject: [Caml-list] Implementation for a (nearly) typesafe shallow option type and a compiler bug?
Date: Sun, 06 May 2012 14:53:14 +0200 [thread overview]
Message-ID: <87sjfd31z9.fsf@frosties.localnet> (raw)
Hi,
as mentioned earlier I wanted to have a
type 'a shallow = NULL | 'a
that is like an 'a option but without the indirection.
The first idea was that no ocaml value can be the C NULL pointer (usualy
all bits set to 0) and the C NULL pointer points outside the ocaml heap
so the GC is fine with that too. So NULL could be encoded as C NULL
pointer and 'a used as is.
First problem is that this does not work for an 'a shallow shallow. And
there is no way to constrain 'a to not be a 'b shallow in the type
definition.
Second problem is that someone else might define a 'a shallow2 type with
the same idea and 'a shallow2 shallow would also not work. And with
abstract types it would be impossible to test for that even if ocaml
would allow negative constraints.
The common problem here is that NULL is not unique for each type. So I
thought of a way to make it unique. What I came up with is using a
functor to create a unique NULL value for each instance. Source code at
the end.
Output:
NULL -> None
Some 5 -> Some 5
NULL -> None
Some NULL -> Some None
Some Some 5 -> Some Some 5
1 2 3 4
a b c d
NULL -> Some 70221466564508
As you can see from the output this solves the problem of 'a shallow
shallow and would also solve the 'a shallow2 shallow case.
But in the last line a new problem appears. Each instance of the functor
has a unique NULL element. But instances of the functor with the same
type are compatible. So an IntShallow2.t can be used instead of an
IntShallow.t but then the NULL does not match.
To me this looks like a bug in ocaml because the resulting type of the
functor application does not match the type I specified for the functor:
module type SHALLOW =
sig
type -'a t
val null : 'a t
val make : 'a -> 'a t
val as_option : 'a t -> 'a option
end
module Make : functor (Type : TYPE) -> SHALLOW
module IntShallow2 :
sig
type 'a t = 'a Shallow.Make(Int).t
val null : 'a t
val make : 'a -> 'a t
val as_option : 'a t -> 'a option
end
The type I specified has 'a t abstract while the IntShallow2 has the
type 'a t more concret.
Restricting the type to what it should already be results in the correct
error:
module IntShallow2 = (Shallow.Make(Int) : Shallow.SHALLOW)
let () =
Printf.printf "NULL -> %s\n" (to_string (IntShallow2.null))
File "shallow.ml", line 91, characters 42-60:
Error: This expression has type 'a IntShallow2.t
but an expression was expected of type
int IntShallow.t = int Shallow.Make(Int).t
Why is that?
MfG
Goswin
======================================================================
module Shallow : sig
module type TYPE = sig type 'a t end
module type SHALLOW =
sig
type -'a t
val null : 'a t
val make : 'a -> 'a t
val as_option : 'a t -> 'a option
end
module type SHALLOWFUNCTOR = functor (Type : TYPE) -> SHALLOW
module Make : functor (Type : TYPE) -> SHALLOW
end = struct
module type TYPE = sig type 'a t end
module type SHALLOW =
sig
type -'a t
val null : 'a t
val make : 'a -> 'a t
val as_option : 'a t -> 'a option
end
module type SHALLOWFUNCTOR = functor (Type : TYPE) -> SHALLOW
module Make_intern =
functor (Type : TYPE) ->
struct
type -'a t
(* Dummy object unique to the type *)
let null = Obj.magic (ref 0)
let make x = Obj.magic x
let as_option x = if x == null then None else Some (Obj.magic x)
end
module Make = (Make_intern : functor (Type : TYPE) -> SHALLOW)
end
module Int = struct type 'a t = int end
module IntShallow = Shallow.Make(Int)
module IntShallowShallow = Shallow.Make(IntShallow)
let to_string x =
match IntShallow.as_option x with
| None -> "None"
| Some x -> Printf.sprintf "Some %d" x
let to_string2 x =
match IntShallowShallow.as_option x with
| None -> "None"
| Some x -> Printf.sprintf "Some %s" (to_string x)
module List = struct
module Item = struct
type 'a t = 'a
end
module Shallow = Shallow.Make(Item)
type 'a item = { mutable next : 'a list; data : 'a; }
and 'a list = 'a item Shallow.t
let null = Shallow.null
let cons x y = Shallow.make { next = y; data = x; }
let rec iter fn x =
match Shallow.as_option x with
| None -> ()
| Some { next; data; } -> fn data; iter fn next
end
let () =
Printf.printf "NULL -> %s\n" (to_string (IntShallow.null));
Printf.printf "Some 5 -> %s\n" (to_string (IntShallow.make 5));
Printf.printf "NULL -> %s\n" (to_string2 (IntShallowShallow.null));
Printf.printf "Some NULL -> %s\n"
(to_string2 (IntShallowShallow.make IntShallow.null));
Printf.printf "Some Some 5 -> %s\n"
(to_string2 (IntShallowShallow.make (IntShallow.make 5)));
let x = List.null in
let x = List.cons 4 x in
let x = List.cons 3 x in
let x = List.cons 2 x in
let x = List.cons 1 x in
List.iter (Printf.printf "%d ") x;
print_newline ();
let y = List.null in
let y = List.cons "d" y in
let y = List.cons "c" y in
let y = List.cons "b" y in
let y = List.cons "a" y in
List.iter (Printf.printf "%s ") y;
print_newline ()
module IntShallow2 = Shallow.Make(Int)
let () =
Printf.printf "NULL -> %s\n" (to_string (IntShallow2.null))
next reply other threads:[~2012-05-06 12:53 UTC|newest]
Thread overview: 5+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-05-06 12:53 Goswin von Brederlow [this message]
2012-05-06 13:11 ` Gabriel Scherer
2012-05-06 15:42 ` Goswin von Brederlow
2012-05-08 18:47 ` Richard W.M. Jones
2012-05-08 18:52 ` Richard W.M. Jones
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=87sjfd31z9.fsf@frosties.localnet \
--to=goswin-v-b@web.de \
--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