From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Original-To: caml-list@sympa.inria.fr Delivered-To: caml-list@sympa.inria.fr Received: from mail2-relais-roc.national.inria.fr (mail2-relais-roc.national.inria.fr [192.134.164.83]) by sympa.inria.fr (Postfix) with ESMTPS id 9FB7D7EE51 for ; Thu, 4 Apr 2013 08:19:21 +0200 (CEST) Received-SPF: None (mail2-smtp-roc.national.inria.fr: no sender authenticity information available from domain of martin.jambon@ens-lyon.org) identity=pra; client-ip=66.111.4.25; receiver=mail2-smtp-roc.national.inria.fr; envelope-from="martin.jambon@ens-lyon.org"; x-sender="martin.jambon@ens-lyon.org"; x-conformance=sidf_compatible Received-SPF: None (mail2-smtp-roc.national.inria.fr: no sender authenticity information available from domain of martin.jambon@ens-lyon.org) identity=mailfrom; client-ip=66.111.4.25; receiver=mail2-smtp-roc.national.inria.fr; envelope-from="martin.jambon@ens-lyon.org"; x-sender="martin.jambon@ens-lyon.org"; x-conformance=sidf_compatible Received-SPF: None (mail2-smtp-roc.national.inria.fr: no sender authenticity information available from domain of postmaster@out1-smtp.messagingengine.com) identity=helo; client-ip=66.111.4.25; receiver=mail2-smtp-roc.national.inria.fr; envelope-from="martin.jambon@ens-lyon.org"; x-sender="postmaster@out1-smtp.messagingengine.com"; x-conformance=sidf_compatible X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: AhsCAIoaXVFCbwQZk2dsb2JhbABDgzwBwQSBDBYOAQEBAQcLCwkUBCSCHwEBBScRCDgBAQ8LGAkWDwkDAgECAUUGDQEHAQEXh3mtC4RBjl4GjmYzB4NAiH2KK4RlhGKONQ X-IPAS-Result: AhsCAIoaXVFCbwQZk2dsb2JhbABDgzwBwQSBDBYOAQEBAQcLCwkUBCSCHwEBBScRCDgBAQ8LGAkWDwkDAgECAUUGDQEHAQEXh3mtC4RBjl4GjmYzB4NAiH2KK4RlhGKONQ X-IronPort-AV: E=Sophos;i="4.87,405,1363129200"; d="scan'208";a="11711669" Received: from out1-smtp.messagingengine.com ([66.111.4.25]) by mail2-smtp-roc.national.inria.fr with ESMTP/TLS/ADH-AES256-SHA; 04 Apr 2013 08:19:20 +0200 Received: from compute1.internal (compute1.nyi.mail.srv.osa [10.202.2.41]) by gateway1.nyi.mail.srv.osa (Postfix) with ESMTP id 4147F20B3D; Thu, 4 Apr 2013 02:19:19 -0400 (EDT) Received: from frontend1.nyi.mail.srv.osa ([10.202.2.160]) by compute1.internal (MEProxy); Thu, 04 Apr 2013 02:19:19 -0400 DKIM-Signature: v=1; a=rsa-sha1; c=relaxed/relaxed; d= messagingengine.com; h=message-id:date:from:mime-version:to:cc :subject:references:in-reply-to:content-type :content-transfer-encoding; s=smtpout; bh=LwNao3YiXDecaIERLCzWsV C0Pao=; b=oWerx/F7aM1w03Xe+Om5taGuPvf7GRVqfSr4uHwcnEGEbn4SefMKX+ WOxF8kwBTq+JbVRx1NMY3x2/YHxdCAXRrbtUBPoYx0X6umW8vydp6qcuKKM65cB7 qFwwYrUNqcN7TgxC7KSpI7rFQBDfImkcXFkaBhX3OdCrGmtatyoK0= X-Sasl-enc: Zzzz9zCpAXjY4IGglf3JNleSo1oFKzBr8JhihrOTQGiS 1365056358 Received: from [192.168.2.4] (unknown [98.248.39.171]) by mail.messagingengine.com (Postfix) with ESMTPA id BBACFC8000A; Thu, 4 Apr 2013 02:19:18 -0400 (EDT) Message-ID: <515D1B65.3070603@ens-lyon.org> Date: Wed, 03 Apr 2013 23:19:17 -0700 From: Martin Jambon User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:17.0) Gecko/17.0 Thunderbird/17.0 MIME-Version: 1.0 To: Anthony Tavener CC: "caml-list@inria.fr" References: In-Reply-To: Content-Type: text/plain; charset=ISO-8859-1; format=flowed Content-Transfer-Encoding: 7bit Subject: Re: [Caml-list] Heterogeneous dictionary Here is an old trick, which is not necessarily useful but fun nonetheless: (* mixtbl.mli *) type 'a t (** A hash table containing values of different types. The type parameter ['a] represents the type of the keys. *) val create : int -> 'a t (** [create n] creates a hash table of initial size [n]. *) val access : unit -> ('a t -> 'a -> 'b option) * ('a t -> 'a -> 'b -> unit) (** Return a pair (get, set) that works for a given type of values. This function is normally called once for each type of value. Several getter/setter pairs may be created for the same type, but a value set with a given setter can only be retrieved with the matching getter. The same getters and setters may be reused across multiple tables. *) (* mixtbl.ml *) type 'a t = ('a, (unit -> unit)) Hashtbl.t let create n = Hashtbl.create n let access () = let r = ref None in let get tbl k = try (Hashtbl.find tbl k) (); let result = !r in r := None; result with Not_found -> None in let set tbl k v = let v_opt = Some v in Hashtbl.replace tbl k (fun () -> r := v_opt) in get, set I put it all on Github: https://github.com/mjambon/mixtbl On 04/03/2013 05:45 PM, Anthony Tavener wrote: > I think I might be up against a brick wall. But maybe there's a door I don't > see, without Obj.magicing myself through the wall. (I haven't had to use > magic > for anything yet!) :) > > I want to stash values under a key, and retrieve them by that key. All > values > bound to a given key are of the same type, but the type will differ between > keys. Basically like a hashtable you'd find in a dynamic language. > > (* modifier-additions like this would be scattered across the > code-base *) > contribute `RecoveryRoll (fun (a,b) -> a+3,b) > contribute `RecoveryRoll (fun (a,b) -> a,b-1) > contribute `ResistPain (fun a -> a+1) > contribute `MagicResistance (fun a -> match a with None -> None | > Some x -> Some(x+3)) > contribute `MagicResistance (fun a -> match a with None -> Some 7 | > Some x -> Some(x+7)) > > (* example of applying modifiers... *) > let modified = fold `RecoveryRoll (4,1) in > ... > > (There are details I've left out here, like the need for 'contribute' > returning an id > by which to remove a modifier, as well as control over > order-of-application.) > > Now I think the type signature of these functions would be: > > val contribute: a'. 'a key -> ('a -> 'a) -> unit > val fold: 'a. 'a key -> 'a -> 'a > > And the thorn in my side would be that the key must be "keyed" to the > type, or > is there an escape? At one point I tried a universal type to "hide" the > signature of the function-list, but I also stashed the inj/proj under > the key > -- well, of course the inj/proj functions had different types per entry in a > hashtable, so that worked as well as not having a universal type > involved. :) > > If I provide the inj/proj functions at each invocation then I need to > pre-create these and house them somewhere (which could create a > bottleneck of > type-dependencies) -- Imagine several hundred modifiers like `RecoveryRoll; > some might use types that only need visibility in one module. Trying to > place > each modifier in suitable modules also seems a mess... a lot of them > conceptually exist "in the spaces between modules". > > So I keep trying to create an airy light-weight "implied" association to > connect modifiers to use-sites... but to satisfy typing it seems I need > to be > explicit at some point. > > Does anyone have any ideas? I'm often surprised at the gymnastics OCaml's > type-system can accomplish under the guidance of some smart folks. If > anyone's > made a heterogenous dictionary/hashtable that doesn't need types explicity > declared, that would probably be what I'm looking for. > > > Note that I've had this problem surface several times and managed to find > solutions that suited the specific problem, but each problem can have it's > subtle details. In this case, the large number of keys and functions, > combined with their spread across codebase and the sparse nature of their > use (a game-entity might have a few dozen modifiers out of hundreds)... > really > seems to push for association-by-name-only. At least that's all my brain > gravitates toward. > > -Tony >