Le 24/03/2012 19:26, Goswin von Brederlow a écrit :
Hi,

consider the code below that counts how often a value is printed.

The reason why this code works is that the memory layout of a
variant with arguments is identical to a record with the same
types. The only difference is that a variant sets the tag of the memory
block to reflect which constructor it is (here Bar = 0, Baz = 1).

But the code is fragile. It requires the use of Obj.magic and duplicates
the definitions of bar and baz (once as variant and once as record). If
the type of foo is changed but not the records then bad things will
happen.

There are ways to do this without Obj.magic:

type foo = Bar of bar_record | Baz of baz_record
type foo = Bar of int * int ref | Baz of float * int ref

The first adds an indirection for every access to foo and breaks
matching. The second adds an indirection for every mutable value in the
type. In both cases the extra indirections increase the memory footprint
and runtime.


So why not allow mutable in variant types and some equivalence with
records? For example:

type<name>  =<Constructor>  of [mutable]<type>[:label] [| ...]

as in:

type foo =
   | Bar of int:i * mutable int:bar_used
   | Baz of float:f * mutable int:baz_used

let use x =
   match x with
     | Bar bar ->
         bar.bar_used<- bar.bar_used + 1
     | Baz baz ->
         baz.baz_used<- baz.baz_used + 1

let print x =
   use x;
   match x with
   | Bar bar ->  Printf.printf "%d\n" bar.i
   | Baz baz ->  Printf.printf "%f\n" baz.f

The label is optional and any types in the constructor without label
would be translated into anonymous fields in a record that are
ineaccessible.

   type foo = Foo of int * mutable int:used

would be equivalent to { _ : int; mutable used : int; }

Taking it one step wurther one could even allow:

let bar = { i = 1; bar_used = 0; }
let foo = Bar bar
let foo = let Bar bar = foo in Bar { bar with i = 2; }


What do you think?

MfG
         Goswin

======================================================================
module Foo : sig
   type foo
   val make_bar : int ->  foo
   val make_baz : float ->  foo
   val get_used : foo ->  int
   val print : foo ->  unit
end = struct
   type foo = Bar of int * int | Baz of float * int
   type bar_record = { i : int; mutable bar_used : int; }
   type baz_record = { f : float; mutable baz_used : int; }

   let make_bar i = Bar (i, 0)
   let make_baz f = Baz (f, 0)

   let use x =
     match x with
     | Bar _ ->
         let (bar : bar_record) = Obj.magic x
         in bar.bar_used<- bar.bar_used + 1
     | Baz _ ->
         let (baz : baz_record) = Obj.magic x
         in baz.baz_used<- baz.baz_used + 1

   let get_used = function Bar (_, used) | Baz (_, used) ->  used

   let print x =
     use x;
     match x with
     | Bar (i, _) ->  Printf.printf "%d\n" i
     | Baz (f, _) ->  Printf.printf "%f\n" f
end;;

let foo = Foo.make_bar 1
let used_before = Foo.get_used foo
let () = Foo.print foo
let used_after = Foo.get_used foo

Hello,

I have been wishing for this for a long time. Mainly because it's just tedious to declare a record for each constructor. Too often do I start with constructors with a low argument count (say 1 to 3) and find that I have to add new arguments. At some point I have so many arguments that I really have to declare the record, and thus rewrite all the relevant parts of the code.

I would add that it would be convenient for me to be able to name only *some* of the arguments. For instance :

type t = Sum of pos: Lexing.position * t * t

I would access the anonymous arguments using pattern-matching as usual, and use ".pos" as a shortcut sometimes.

Unifying records and sums is great, unifying tuples at the same time seems even better to me. The OPA language (of Mlstate) does this, if I'm not mistaken.

Cheers,

--
Romain Bardou

--
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