Sorry for all these mails.
Looks like I don't think well when I'm sleepy...

Anyway, I think that at last I have a reasonable (much simpler) solution.
This still uses sopt_tag (i.e. lazy_tag-1), but this time the argument is
the number of "some" constructors, so there is no extra cost for marshaling.
The only values on which Sopt.some is not the identity are those with a
single argument, which is additionally represented by an integer between 0 and 
last.
Moreover, even if for some reason you build such a value using a real sum
type, you still have Sopt.arg (Sopt.some v) = v, the only change being a loss
of sharing (which is anyway not guaranteed by the ocaml specification).

Jacques

module Sopt : sig
 type +'a t
 val none : 'a t
 val some : 'a -> 'a t
 val is_none : 'a t -> bool
 val arg  : 'a t -> 'a
 val depth : 'a t -> int
end = struct
 type 'a t = Obj.t
 let sopt_tag = Obj.lazy_tag - 1
 let none = Obj.new_block sopt_tag 1
 let last = 255
 let area = Array.create (last+1) none
 let () =
   Obj.set_field none 0 (Obj.repr 0);
   for i = 1 to last do
     let stub = Obj.new_block sopt_tag 1 in
     Obj.set_field stub 0 (Obj.repr i);
     area.(i) <- stub
   done
 let is_none x = (x = none)
 let is_sopt x =
   Obj.is_block x && Obj.tag x = sopt_tag && Obj.size x = 1 &&
   let i = Obj.obj (Obj.field x 0) in i >= 0 && i <= last
 let depth x =
   let x = Obj.repr x in
   if is_sopt x then Obj.obj (Obj.field x 0) else -1
 let some (x : 'a) : 'a t =
   let i = depth x in
   if i < 0 then Obj.magic x else
   if i = last then invalid_arg "Sopt.some" else Obj.obj area.(i+1)
 let arg (x : 'a t) : 'a =
   let i = depth x in
   if i < 0 then Obj.magic x else
   if i = 0 then invalid_arg "Sopt.arg" else Obj.obj area.(i-1)
end



-- 
Caml-list mailing list.  Subscription management and archives:
https://sympa-roc.inria.fr/wws/info/caml-list
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
Bug reports: http://caml.inria.fr/bin/caml-bugs

Reply via email to