caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
From: Jacques Garrigue <garrigue@math.nagoya-u.ac.jp>
To: colanderman@gmail.com
Cc: caml-list@inria.fr
Subject: Re: [Caml-list] Sparse structure
Date: Fri, 08 Jul 2005 09:57:44 +0900 (JST)	[thread overview]
Message-ID: <20050708.095744.108119733.garrigue@math.nagoya-u.ac.jp> (raw)
In-Reply-To: <875c7e0705070712273e4231a9@mail.gmail.com>

From: Chris King <colanderman@gmail.com>

> I'm trying to create a sparse structure; i.e. a large structure which
> doesn't allocate storage for "unused" fields.  Given a structure:
> 
> type foo = { a: int option; b: float option }
> 
> the best solution I can come up with, short of using Obj.magic, is to
> use a hash table like this:
> 
> type foo_key = A_key | B_key
> type foo_value = A_value of int | B_value of float
> type sparse = (foo_key, foo_value) Hashtbl.t
> 
> which works, but the extra variant type required means more CPU time
> and more keystrokes.  Is there a better solution than this?
> 
> The structure will have hundreds of fields, each with a different
> type.  Most of the fields will be unused, but usage will be determined
> at runtime so using objects is not an option.

This is a classical problem, with no good solution that I know.

If you want to avoid Obj.magic, then your solution seems OK, yet
* if your values are really sparse, Map might be better than Hashtbl
  (more compact representation)
* if you have really hundreds of fields, then you have better switch
  to polymorphic variants, as normal ones only allow about 240 cases.

If you are ready to use a bit of Obj, then there are some other
solutions.
For instance, you could do something like this.

module Int = struct type t = int let compare : int -> int -> int = compare end
module M = Map.Make(Int)
type +'a elt
type 'a map = 'a elt M.t

let addA (x : 'a) (m : [> `A of 'a] map) =
  M.add (Obj.magic `A) (Obj.magic x) m

let addB (x : 'a) (m : [> `B of 'a] map) =
  M.add (Obj.magic `B) (Obj.magic x) m

let getA (m : [> `A of 'a] map) : 'a =
  Obj.magic (M.find (Obj.magic `A) m)

let getB (m : [> `B of 'a] map) : 'a =
  Obj.magic (M.find (Obj.magic `B) m)

Note that the result is completely type safe, and you don't need all
maps to contain the same potential fields.
The downside is that you need to define set and get for all fields.
On the other hand, it should be easy to define camlp4 macros
enforcing the same type annotations, avoiding such definitions.

(Polymorphic variants here are only used as phantom types. Note
however that this choice is useful: it ensures that two keys cannot
conflict, as if `A and `B had the same hash values, this would be
detected when constructing the type [> `A of 'a | `B of 'b])

Jacques Garrigue


  parent reply	other threads:[~2005-07-08  0:57 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2005-07-07 19:27 Chris King
     [not found] ` <1120765639.9384.42.camel@titania>
2005-07-07 20:04   ` [Caml-list] " Chris King
     [not found] ` <87r7eamlv9.fsf@linux-france.org>
2005-07-07 20:16   ` Chris King
2005-07-08  0:57 ` Jacques Garrigue [this message]
2005-07-08 13:29   ` Chris King
2005-07-08 23:29     ` 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=20050708.095744.108119733.garrigue@math.nagoya-u.ac.jp \
    --to=garrigue@math.nagoya-u.ac.jp \
    --cc=caml-list@inria.fr \
    --cc=colanderman@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).