caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
* [Caml-list] Heterogeneous dictionary
@ 2013-04-04  0:45 Anthony Tavener
  2013-04-04  1:29 ` Yaron Minsky
                   ` (2 more replies)
  0 siblings, 3 replies; 17+ messages in thread
From: Anthony Tavener @ 2013-04-04  0:45 UTC (permalink / raw)
  To: caml-list

[-- Attachment #1: Type: text/plain, Size: 2942 bytes --]

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

[-- Attachment #2: Type: text/html, Size: 3840 bytes --]

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [Caml-list] Heterogeneous dictionary
  2013-04-04  0:45 [Caml-list] Heterogeneous dictionary Anthony Tavener
@ 2013-04-04  1:29 ` Yaron Minsky
  2013-04-04  2:18   ` Anthony Tavener
  2013-04-04  6:19 ` Martin Jambon
  2013-04-04  7:38 ` Raphaël Proust
  2 siblings, 1 reply; 17+ messages in thread
From: Yaron Minsky @ 2013-04-04  1:29 UTC (permalink / raw)
  To: Anthony Tavener; +Cc: caml-list

Have you looked at Univ_map in Core?  It has the same problem you're
complaining about, in that the keys do need to be tied to the type of
the data stored under that key.  You then of course need to stash the
key somewhere.  But I'm not sure what problem that creates.  In
particular, I don't know why this creates a bottleneck of type
dependencies.  Each Univ_map.Key.t is created independently, and can
be created at any point in the code.

y

On Wed, Apr 3, 2013 at 8:45 PM, Anthony Tavener
<anthony.tavener@gmail.com> 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.

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [Caml-list] Heterogeneous dictionary
  2013-04-04  1:29 ` Yaron Minsky
@ 2013-04-04  2:18   ` Anthony Tavener
  0 siblings, 0 replies; 17+ messages in thread
From: Anthony Tavener @ 2013-04-04  2:18 UTC (permalink / raw)
  To: Yaron Minsky; +Cc: caml-list

[-- Attachment #1: Type: text/plain, Size: 5000 bytes --]

Oh, maybe I created a limitation in my own head...

Would this work then (for example):

module Modifier = struct
  let recovery = Key.create "recovery"
  let resist_pain = Key.create "resist_pain"
  let resist_magic = Key.create "resist_magic"
  (* a whole lot of these... *)
end

These would then be monomorphic? Anyway, the important thing is
they didn't require knowledge of any types to create all the keys, so
now having all other modules referencing Modifier wouldn't be bad at all.

Then something like the following will reify the type of the
Modifier.recovery key?

  let mods = set mods Modifier.recovery (fun (a,b) -> a+6,b) in ...

I kept thinking that if I had a "grand central" of universal embeddors
they'd need to be aware of the types they're embedding... thereby
creating the type-dependencies I was worried about!

This solution, if I'm understanding it right, is perfectly fine!
Thank-you for cluing me in, Yaron!



On Wed, Apr 3, 2013 at 7:29 PM, Yaron Minsky <yminsky@janestreet.com> wrote:

> Have you looked at Univ_map in Core?  It has the same problem you're
> complaining about, in that the keys do need to be tied to the type of
> the data stored under that key.  You then of course need to stash the
> key somewhere.  But I'm not sure what problem that creates.  In
> particular, I don't know why this creates a bottleneck of type
> dependencies.  Each Univ_map.Key.t is created independently, and can
> be created at any point in the code.
>
> y
>
> On Wed, Apr 3, 2013 at 8:45 PM, Anthony Tavener
> <anthony.tavener@gmail.com> 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.
>
> --
> Caml-list mailing list.  Subscription management and archives:
> https://sympa.inria.fr/sympa/arc/caml-list
> Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
> Bug reports: http://caml.inria.fr/bin/caml-bugs
>

[-- Attachment #2: Type: text/html, Size: 6822 bytes --]

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [Caml-list] Heterogeneous dictionary
  2013-04-04  0:45 [Caml-list] Heterogeneous dictionary Anthony Tavener
  2013-04-04  1:29 ` Yaron Minsky
@ 2013-04-04  6:19 ` Martin Jambon
  2013-04-04  7:32   ` Alain Frisch
  2013-04-04  7:38 ` Raphaël Proust
  2 siblings, 1 reply; 17+ messages in thread
From: Martin Jambon @ 2013-04-04  6:19 UTC (permalink / raw)
  To: Anthony Tavener; +Cc: caml-list

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
>


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [Caml-list] Heterogeneous dictionary
  2013-04-04  6:19 ` Martin Jambon
@ 2013-04-04  7:32   ` Alain Frisch
  2013-04-04 18:16     ` Martin Jambon
  0 siblings, 1 reply; 17+ messages in thread
From: Alain Frisch @ 2013-04-04  7:32 UTC (permalink / raw)
  To: Martin Jambon, Anthony Tavener; +Cc: caml-list

On 04/04/2013 08:19 AM, Martin Jambon wrote:
> 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

Careful, this is buggy!  If you apply the "get" on an existing value 
with the "wrong" type, it will set the slot corresponding to that wrong 
type, which can result in a fake "get" later on that type.

# let h = create 10;;
val h : '_a X.t = <abstr>
# let (get1, set1) = access ();;
val get1 : '_a X.t -> '_a -> '_b option = <fun>
val set1 : '_a X.t -> '_a -> '_b -> unit = <fun>
# let (get2, set2) = access ();;
val get2 : '_a X.t -> '_a -> '_b option = <fun>
val set2 : '_a X.t -> '_a -> '_b -> unit = <fun>
# set1 h "a" true;;
- : unit = ()
# set2 h "b" "X";;
- : unit = ()
# get1 h "b";;
- : bool option = None
(*  ====> the slot for get2/set2 has been filled! *)

# get2 h "a";;
- : string option = Some "X"

(* WRONG! *)


Here is an implementation of the same interface based on local 
exceptions.  It avoids the bug above and it is also more efficient and 
thread-safe:


type 'a t = ('a, exn) Hashtbl.t

let create n = Hashtbl.create n

let access (type t) () =
   let module M = struct exception E of t end in
   let r = ref None in
   let get tbl k =
     try
       match Hashtbl.find tbl k with
       | M.E x -> Some x
       | _ -> None
     with Not_found -> None
   in
   let set tbl k v =
     Hashtbl.replace tbl k (M.E v)
   in
   get, set

(If [get] is more frequent than [set], it is worth storing a "t option" 
in the exception directly.)

-- Alain

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [Caml-list] Heterogeneous dictionary
  2013-04-04  0:45 [Caml-list] Heterogeneous dictionary Anthony Tavener
  2013-04-04  1:29 ` Yaron Minsky
  2013-04-04  6:19 ` Martin Jambon
@ 2013-04-04  7:38 ` Raphaël Proust
  2013-04-04  8:37   ` Anthony Tavener
  2 siblings, 1 reply; 17+ messages in thread
From: Raphaël Proust @ 2013-04-04  7:38 UTC (permalink / raw)
  To: Anthony Tavener; +Cc: caml-list

On Thu, Apr 4, 2013 at 1:45 AM, Anthony Tavener
<anthony.tavener@gmail.com> wrote:
> […]

And yet-another-solution, Ocsigen's Polytable:
http://ocsigen.org/ocsigenserver/api/Polytables


Cheers,
-- 
______________
Raphaël Proust

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [Caml-list] Heterogeneous dictionary
  2013-04-04  7:38 ` Raphaël Proust
@ 2013-04-04  8:37   ` Anthony Tavener
  2013-04-04  9:04     ` David House
  0 siblings, 1 reply; 17+ messages in thread
From: Anthony Tavener @ 2013-04-04  8:37 UTC (permalink / raw)
  To: Raphaël Proust; +Cc: caml-list

[-- Attachment #1: Type: text/plain, Size: 1866 bytes --]

Thank-you for the advice and pointers, folks...

Well, the common problem is still the same one I've been struggling with:
"creating keys", and having to access them.

I can't create keys "type-free" in a common module. As I figured... having "
modifier.ml" with a bunch of Key.create will have monomorphic types which
can't be resolved since with no usage in that module to make the type
concrete. I had a nagging feeling I'd need a "whole-program" compiler...

Instead I'd have to create keys in modules where they are used... but then
I might have a mess of keys like Wounds.recovery, Combat.resist_pain, ...
the problem being that only a fraction of these keys actually make sense
being associated to a particular module, and it gets confusing to know
which (of several candidates) I decided to stash them into. This was the
attraction to polymorphic variants (which I rarely use) -- they give a
pre-ordained unique ID based on a simple name... no declaration, and no
module prefixing, which seems important to me for this case.

Note that I have a "database" of tables with different types (implemented
by first-class modules!), and it works great for the bulk of my game-state,
but each table is well-populated and heavily used in consistent manner.
These modifiers though... they're a bit like ad-hoc message passing, where
I can submit any message and anywhere else add a snippet of code to
interpret it (not that I have any of that going on, otherwise it might hold
the solution!).



On Thu, Apr 4, 2013 at 1:38 AM, Raphaël Proust <raphlalou@gmail.com> wrote:

> On Thu, Apr 4, 2013 at 1:45 AM, Anthony Tavener
> <anthony.tavener@gmail.com> wrote:
> > […]
>
> And yet-another-solution, Ocsigen's Polytable:
> http://ocsigen.org/ocsigenserver/api/Polytables
>
>
> Cheers,
> --
> ______________
> Raphaël Proust
>

[-- Attachment #2: Type: text/html, Size: 2625 bytes --]

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [Caml-list] Heterogeneous dictionary
  2013-04-04  8:37   ` Anthony Tavener
@ 2013-04-04  9:04     ` David House
  2013-04-04 18:48       ` Anthony Tavener
  0 siblings, 1 reply; 17+ messages in thread
From: David House @ 2013-04-04  9:04 UTC (permalink / raw)
  To: Anthony Tavener; +Cc: Raphaël Proust, caml-list

I don't quite understand the problem. Here's an example of how one
might use univ_map:

open Core.Std

module Keys : sig
  val recovery : int Univ_map.Key.t
  val resist_pain : float  Univ_map.Key.t
end = struct
  let recovery = Univ_key.Key.create "recovery" Int.sexp_of_t
  let resist_pain = Univ_key.Key.create "resist_pain" Float.sexp_of_t
end

(In practice this might be two files: keys.ml with the implementation
and keys.mli with the signature.) You can then add things as follows:

let add map ~key ~data = Univ_map.add_exn map key data in
let map =
  Univ_map.empty
  |> add ~key:Keys.recovery ~data:4
  |> add ~key:Keys.resist_pain ~data:10.
in
...

On 4 April 2013 09:37, Anthony Tavener <anthony.tavener@gmail.com> wrote:
> Thank-you for the advice and pointers, folks...
>
> Well, the common problem is still the same one I've been struggling with:
> "creating keys", and having to access them.
>
> I can't create keys "type-free" in a common module. As I figured... having
> "modifier.ml" with a bunch of Key.create will have monomorphic types which
> can't be resolved since with no usage in that module to make the type
> concrete. I had a nagging feeling I'd need a "whole-program" compiler...
>
> Instead I'd have to create keys in modules where they are used... but then I
> might have a mess of keys like Wounds.recovery, Combat.resist_pain, ... the
> problem being that only a fraction of these keys actually make sense being
> associated to a particular module, and it gets confusing to know which (of
> several candidates) I decided to stash them into. This was the attraction to
> polymorphic variants (which I rarely use) -- they give a pre-ordained unique
> ID based on a simple name... no declaration, and no module prefixing, which
> seems important to me for this case.
>
> Note that I have a "database" of tables with different types (implemented by
> first-class modules!), and it works great for the bulk of my game-state, but
> each table is well-populated and heavily used in consistent manner. These
> modifiers though... they're a bit like ad-hoc message passing, where I can
> submit any message and anywhere else add a snippet of code to interpret it
> (not that I have any of that going on, otherwise it might hold the
> solution!).
>
>
>
> On Thu, Apr 4, 2013 at 1:38 AM, Raphaël Proust <raphlalou@gmail.com> wrote:
>>
>> On Thu, Apr 4, 2013 at 1:45 AM, Anthony Tavener
>> <anthony.tavener@gmail.com> wrote:
>> > […]
>>
>> And yet-another-solution, Ocsigen's Polytable:
>> http://ocsigen.org/ocsigenserver/api/Polytables
>>
>>
>> Cheers,
>> --
>> ______________
>> Raphaël Proust
>
>

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [Caml-list] Heterogeneous dictionary
  2013-04-04  7:32   ` Alain Frisch
@ 2013-04-04 18:16     ` Martin Jambon
  0 siblings, 0 replies; 17+ messages in thread
From: Martin Jambon @ 2013-04-04 18:16 UTC (permalink / raw)
  To: Alain Frisch; +Cc: Anthony Tavener, caml-list

On 04/04/2013 12:32 AM, Alain Frisch wrote:
> On 04/04/2013 08:19 AM, Martin Jambon wrote:
>> 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
>
> Careful, this is buggy!  If you apply the "get" on an existing value
> with the "wrong" type, it will set the slot corresponding to that wrong
> type, which can result in a fake "get" later on that type.
>
> # let h = create 10;;
> val h : '_a X.t = <abstr>
> # let (get1, set1) = access ();;
> val get1 : '_a X.t -> '_a -> '_b option = <fun>
> val set1 : '_a X.t -> '_a -> '_b -> unit = <fun>
> # let (get2, set2) = access ();;
> val get2 : '_a X.t -> '_a -> '_b option = <fun>
> val set2 : '_a X.t -> '_a -> '_b -> unit = <fun>
> # set1 h "a" true;;
> - : unit = ()
> # set2 h "b" "X";;
> - : unit = ()
> # get1 h "b";;
> - : bool option = None
> (*  ====> the slot for get2/set2 has been filled! *)
>
> # get2 h "a";;
> - : string option = Some "X"
>
> (* WRONG! *)

Oops. Here is my corrected version:

let access () =
   let r = ref None in
   let get tbl k =
     r := None; (* reset state in case last operation was not a get *)
     try
       (Hashtbl.find tbl k) ();
       let result = !r in
       r := None; (* clean up here in order avoid memory leak *)
       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


> Here is an implementation of the same interface based on local
> exceptions.  It avoids the bug above and it is also more efficient and
> thread-safe:
>
>
> type 'a t = ('a, exn) Hashtbl.t
>
> let create n = Hashtbl.create n
>
> let access (type t) () =
>    let module M = struct exception E of t end in
>    let r = ref None in
>    let get tbl k =
>      try
>        match Hashtbl.find tbl k with
>        | M.E x -> Some x
>        | _ -> None
>      with Not_found -> None
>    in
>    let set tbl k v =
>      Hashtbl.replace tbl k (M.E v)
>    in
>    get, set
>
> (If [get] is more frequent than [set], it is worth storing a "t option"
> in the exception directly.)

Nice.


^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [Caml-list] Heterogeneous dictionary
  2013-04-04  9:04     ` David House
@ 2013-04-04 18:48       ` Anthony Tavener
  2013-04-05 16:37         ` Yaron Minsky
  0 siblings, 1 reply; 17+ messages in thread
From: Anthony Tavener @ 2013-04-04 18:48 UTC (permalink / raw)
  To: David House; +Cc: caml-list

[-- Attachment #1: Type: text/plain, Size: 6006 bytes --]

The problem here...

  module Keys : sig
    val recovery : int Univ_map.Key.t
    val resist_pain : float  Univ_map.Key.t
    ...

Would be that Keys would now have dependence on types spanning the codebase.

Say these modifiers use Wounds.t, Fatigue.t, Ability.Score.t, ... There are
a
lot of types, which mostly have a limited scope (their own module and a few
others). Wouldn't it be a problem to have all types brought into this one
module, which every other module also becomes dependent on? Maybe it just
feels like a problem but it's just an aesthetic -- Would you do this? A few
hundred keys involving types from half the modules of the codebase?


I'm trying to use these "modifiers" for code organisation -- declaring
snippets of functionality (all of signature 'a -> 'a... to return modified
input) in a lightweight manner, which can be applied elsewhere.

For example, the Virtue module can add a lot of modifers to an entity (UID).
Say one entity has virtues of Agility, Inspirational, and Sun-cyclic Magic,
which each adding a few modifier functions keyed to various contexts
(sun-cyclic magic: "Casting" is +3 while the sun is up). The associated
modifiers would be picked up in code spread throughout the application.
Rules
for combat, spellcasting, even character dialog...

Rather than having character dialog checking for "does he have this virtue,
or
that one? How about this ability? Spell-effects? Reputations? ..." I want to
apply all appropriate/active modifiers for entity and situation which come
from other rules. So, dialog code might have a current_value, then...
eg.
  let modified_value = apply_modifiers_for_context entity `CharmRoll
current_value

There is a lot of work on my project which I've been avoiding because the
direct approach is building hairy nests of checks which call out to code
everywhere... effectively splitting logic between the point of origin of a
rule, and the point of application of it. I'd rather declare the individual
rules, each in one piece, and "magically" apply the aggregate of rules.


In a way, what I'm looking for is having a grand-central lookup, which
*trusts* that I'm using the right keys at the right time (where the keys are
purely symbolic with no type info)... but it would be nice if once the whole
program is compiled it could identify whether that trust was broken
afterall.
A bit of a pipe-dream, and maybe even flawed logic. :)

It might sound like I'm being too picky or even whiney... that declaring
keys
throughout the code is unacceptable, or having a file dependent on all types
is problematic... maybe I am? The first seems disorganised and adds a
mental burden to deciding and knowing where keys live; the second is a
problem, isn't it?

Dynamic languages can do what I want at the cost of typesafety. So I might
just prefer to make that same tradeoff for one mechanism in my code...
"famous
last words"? I hope not. I hope it just works and I don't have nightmares
about lurking segfaults. :)


On Thu, Apr 4, 2013 at 3:04 AM, David House <dhouse@janestreet.com> wrote:

> I don't quite understand the problem. Here's an example of how one
> might use univ_map:
>
> open Core.Std
>
> module Keys : sig
>   val recovery : int Univ_map.Key.t
>   val resist_pain : float  Univ_map.Key.t
> end = struct
>   let recovery = Univ_key.Key.create "recovery" Int.sexp_of_t
>   let resist_pain = Univ_key.Key.create "resist_pain" Float.sexp_of_t
> end
>
> (In practice this might be two files: keys.ml with the implementation
> and keys.mli with the signature.) You can then add things as follows:
>
> let add map ~key ~data = Univ_map.add_exn map key data in
> let map =
>   Univ_map.empty
>   |> add ~key:Keys.recovery ~data:4
>   |> add ~key:Keys.resist_pain ~data:10.
> in
> ...
>
> On 4 April 2013 09:37, Anthony Tavener <anthony.tavener@gmail.com> wrote:
> > Thank-you for the advice and pointers, folks...
> >
> > Well, the common problem is still the same one I've been struggling with:
> > "creating keys", and having to access them.
> >
> > I can't create keys "type-free" in a common module. As I figured...
> having
> > "modifier.ml" with a bunch of Key.create will have monomorphic types
> which
> > can't be resolved since with no usage in that module to make the type
> > concrete. I had a nagging feeling I'd need a "whole-program" compiler...
> >
> > Instead I'd have to create keys in modules where they are used... but
> then I
> > might have a mess of keys like Wounds.recovery, Combat.resist_pain, ...
> the
> > problem being that only a fraction of these keys actually make sense
> being
> > associated to a particular module, and it gets confusing to know which
> (of
> > several candidates) I decided to stash them into. This was the
> attraction to
> > polymorphic variants (which I rarely use) -- they give a pre-ordained
> unique
> > ID based on a simple name... no declaration, and no module prefixing,
> which
> > seems important to me for this case.
> >
> > Note that I have a "database" of tables with different types
> (implemented by
> > first-class modules!), and it works great for the bulk of my game-state,
> but
> > each table is well-populated and heavily used in consistent manner. These
> > modifiers though... they're a bit like ad-hoc message passing, where I
> can
> > submit any message and anywhere else add a snippet of code to interpret
> it
> > (not that I have any of that going on, otherwise it might hold the
> > solution!).
> >
> >
> >
> > On Thu, Apr 4, 2013 at 1:38 AM, Raphaël Proust <raphlalou@gmail.com>
> wrote:
> >>
> >> On Thu, Apr 4, 2013 at 1:45 AM, Anthony Tavener
> >> <anthony.tavener@gmail.com> wrote:
> >> > […]
> >>
> >> And yet-another-solution, Ocsigen's Polytable:
> >> http://ocsigen.org/ocsigenserver/api/Polytables
> >>
> >>
> >> Cheers,
> >> --
> >> ______________
> >> Raphaël Proust
> >
> >
>

[-- Attachment #2: Type: text/html, Size: 7792 bytes --]

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [Caml-list] Heterogeneous dictionary
  2013-04-04 18:48       ` Anthony Tavener
@ 2013-04-05 16:37         ` Yaron Minsky
  2013-04-05 18:27           ` Anthony Tavener
  0 siblings, 1 reply; 17+ messages in thread
From: Yaron Minsky @ 2013-04-05 16:37 UTC (permalink / raw)
  To: Anthony Tavener; +Cc: David House, caml-list

On Thu, Apr 4, 2013 at 2:48 PM, Anthony Tavener
<anthony.tavener@gmail.com> wrote:
> The problem here...
>
>   module Keys : sig
>     val recovery : int Univ_map.Key.t
>     val resist_pain : float  Univ_map.Key.t
>     ...
>
> Would be that Keys would now have dependence on types spanning the codebase.

Sure, but there's nothing that requires these to be stored together.
They can be scattered to the four winds, and yet all used to keep
things in the same Univ_map.t.

It's honestly very much like using a dynamic language, where you get
to declare new items at will that can be cast in and out from a
universal type.

It's probably worth reading over the Univ module in Core as well,
since Univ_map is built on it, and if Univ_map doesn't quite do what
you want, you can probably built what you need precisely on top of
Univ.

> Say these modifiers use Wounds.t, Fatigue.t, Ability.Score.t, ... There are
> a
> lot of types, which mostly have a limited scope (their own module and a few
> others). Wouldn't it be a problem to have all types brought into this one
> module, which every other module also becomes dependent on? Maybe it just
> feels like a problem but it's just an aesthetic -- Would you do this? A few
> hundred keys involving types from half the modules of the codebase?
>
>
> I'm trying to use these "modifiers" for code organisation -- declaring
> snippets of functionality (all of signature 'a -> 'a... to return modified
> input) in a lightweight manner, which can be applied elsewhere.
>
> For example, the Virtue module can add a lot of modifers to an entity (UID).
> Say one entity has virtues of Agility, Inspirational, and Sun-cyclic Magic,
> which each adding a few modifier functions keyed to various contexts
> (sun-cyclic magic: "Casting" is +3 while the sun is up). The associated
> modifiers would be picked up in code spread throughout the application.
> Rules
> for combat, spellcasting, even character dialog...
>
> Rather than having character dialog checking for "does he have this virtue,
> or
> that one? How about this ability? Spell-effects? Reputations? ..." I want to
> apply all appropriate/active modifiers for entity and situation which come
> from other rules. So, dialog code might have a current_value, then...
> eg.
>   let modified_value = apply_modifiers_for_context entity `CharmRoll
> current_value
>
> There is a lot of work on my project which I've been avoiding because the
> direct approach is building hairy nests of checks which call out to code
> everywhere... effectively splitting logic between the point of origin of a
> rule, and the point of application of it. I'd rather declare the individual
> rules, each in one piece, and "magically" apply the aggregate of rules.
>
>
> In a way, what I'm looking for is having a grand-central lookup, which
> *trusts* that I'm using the right keys at the right time (where the keys are
> purely symbolic with no type info)... but it would be nice if once the whole
> program is compiled it could identify whether that trust was broken
> afterall.
> A bit of a pipe-dream, and maybe even flawed logic. :)
>
> It might sound like I'm being too picky or even whiney... that declaring
> keys
> throughout the code is unacceptable, or having a file dependent on all types
> is problematic... maybe I am? The first seems disorganised and adds a
> mental burden to deciding and knowing where keys live; the second is a
> problem, isn't it?
>
> Dynamic languages can do what I want at the cost of typesafety. So I might
> just prefer to make that same tradeoff for one mechanism in my code...
> "famous
> last words"? I hope not. I hope it just works and I don't have nightmares
> about lurking segfaults. :)
>
>
> On Thu, Apr 4, 2013 at 3:04 AM, David House <dhouse@janestreet.com> wrote:
>>
>> I don't quite understand the problem. Here's an example of how one
>> might use univ_map:
>>
>> open Core.Std
>>
>> module Keys : sig
>>   val recovery : int Univ_map.Key.t
>>   val resist_pain : float  Univ_map.Key.t
>> end = struct
>>   let recovery = Univ_key.Key.create "recovery" Int.sexp_of_t
>>   let resist_pain = Univ_key.Key.create "resist_pain" Float.sexp_of_t
>> end
>>
>> (In practice this might be two files: keys.ml with the implementation
>> and keys.mli with the signature.) You can then add things as follows:
>>
>> let add map ~key ~data = Univ_map.add_exn map key data in
>> let map =
>>   Univ_map.empty
>>   |> add ~key:Keys.recovery ~data:4
>>   |> add ~key:Keys.resist_pain ~data:10.
>> in
>> ...
>>
>> On 4 April 2013 09:37, Anthony Tavener <anthony.tavener@gmail.com> wrote:
>> > Thank-you for the advice and pointers, folks...
>> >
>> > Well, the common problem is still the same one I've been struggling
>> > with:
>> > "creating keys", and having to access them.
>> >
>> > I can't create keys "type-free" in a common module. As I figured...
>> > having
>> > "modifier.ml" with a bunch of Key.create will have monomorphic types
>> > which
>> > can't be resolved since with no usage in that module to make the type
>> > concrete. I had a nagging feeling I'd need a "whole-program" compiler...
>> >
>> > Instead I'd have to create keys in modules where they are used... but
>> > then I
>> > might have a mess of keys like Wounds.recovery, Combat.resist_pain, ...
>> > the
>> > problem being that only a fraction of these keys actually make sense
>> > being
>> > associated to a particular module, and it gets confusing to know which
>> > (of
>> > several candidates) I decided to stash them into. This was the
>> > attraction to
>> > polymorphic variants (which I rarely use) -- they give a pre-ordained
>> > unique
>> > ID based on a simple name... no declaration, and no module prefixing,
>> > which
>> > seems important to me for this case.
>> >
>> > Note that I have a "database" of tables with different types
>> > (implemented by
>> > first-class modules!), and it works great for the bulk of my game-state,
>> > but
>> > each table is well-populated and heavily used in consistent manner.
>> > These
>> > modifiers though... they're a bit like ad-hoc message passing, where I
>> > can
>> > submit any message and anywhere else add a snippet of code to interpret
>> > it
>> > (not that I have any of that going on, otherwise it might hold the
>> > solution!).
>> >
>> >
>> >
>> > On Thu, Apr 4, 2013 at 1:38 AM, Raphaël Proust <raphlalou@gmail.com>
>> > wrote:
>> >>
>> >> On Thu, Apr 4, 2013 at 1:45 AM, Anthony Tavener
>> >> <anthony.tavener@gmail.com> wrote:
>> >> > […]
>> >>
>> >> And yet-another-solution, Ocsigen's Polytable:
>> >> http://ocsigen.org/ocsigenserver/api/Polytables
>> >>
>> >>
>> >> Cheers,
>> >> --
>> >> ______________
>> >> Raphaël Proust
>> >
>> >
>
>

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [Caml-list] Heterogeneous dictionary
  2013-04-05 16:37         ` Yaron Minsky
@ 2013-04-05 18:27           ` Anthony Tavener
  2013-04-05 18:51             ` Yaron Minsky
  0 siblings, 1 reply; 17+ messages in thread
From: Anthony Tavener @ 2013-04-05 18:27 UTC (permalink / raw)
  To: Yaron Minsky; +Cc: caml-list

[-- Attachment #1: Type: text/plain, Size: 10488 bytes --]

> Sure, but there's nothing that requires these to be stored together.
> They can be scattered to the four winds, and yet all used to keep
> things in the same Univ_map.t.

I was working with a universal type, but that was exactly the problem I
encountered: I need to create the keys and hold them somewhere. My original
post might have been unclear, sorry. This is what I meant by having to
pre-create the inj/proj pair and house them somewhere... where a single file
would create a bottleneck of types, or scattered becomes a "mess". Scattered
would prove confusing I think... with hundreds of keys that have no sensible
"home" module. Well, some might make sense, but most of these keys are
interstitial -- between modules, somewhat like messages. I was trying to map
out where various keys would live and it wasn't obvious and would continue
to
be unclear when I wanted to use a key. There would be cognitive burden of
deciding home modules for things which don't fit into the modular namespace.

So, a universal type with "keys" does solve the problem, for some
definition of
solved. My concern is that the solution is too cumbersome and confusing in
this use-case. Very much like arguments for polymorphic variants versus
variants. Unfortunately I don't see any way to "embed type" in a polymorphic
variant (I did check whether hashes could match between different function
implementations of same type-signature... which was kind of silly because
I'm
pretty sure the function address would be used in the hashvalue). Although
I imagine types do have hashvalues at some point in the compiler!

Another (failed?) possibility I mentioned as a pipe-dream: if "keys" could
be
left open "to trust", and then verified that all trusted usages lined up at
link-time. After you're first reply (Yaron), I thought for a moment that
monomorphic types might work like that -- resolved at link time. Of course,
they're not, as a test quickly confirmed. :( But... that's why I asked the
wise body of OCamlers if you have ideas -- I don't have a complete grasp of
the language and might be missing something or have a false assumption.
It's a
complex type-system! I like it a lot though.

Thinking more about this, and formulating these replies, I've realized
there's
a common idiom in game development -- and maybe software in general?  It's
use
of string-hashes to create flexible associations... from code to code, or
code
to data (I think that's how it starts... you need to share "IDs" between
code
and data -- and then the technique spreads).  Messages, names of special
points in artwork (eg "primary-grip"), effects, things accessible by
script...
But with such extensive usage, you need tools to verify correct usage as
much
as possible. C, of course, provides few guarantees of anything, so you write
your own tools. OCaml is tantalizing with its rich typesystem -- and
polymorphic variants are like built-in string-hash support. So I kept trying
to figure out a way to get OCaml to do the heavy lifting... for idioms I
might
be unreasonably stuck on. ;)



On Fri, Apr 5, 2013 at 10:37 AM, Yaron Minsky <yminsky@janestreet.com>wrote:

> On Thu, Apr 4, 2013 at 2:48 PM, Anthony Tavener
> <anthony.tavener@gmail.com> wrote:
> > The problem here...
> >
> >   module Keys : sig
> >     val recovery : int Univ_map.Key.t
> >     val resist_pain : float  Univ_map.Key.t
> >     ...
> >
> > Would be that Keys would now have dependence on types spanning the
> codebase.
>
> Sure, but there's nothing that requires these to be stored together.
> They can be scattered to the four winds, and yet all used to keep
> things in the same Univ_map.t.
>
> It's honestly very much like using a dynamic language, where you get
> to declare new items at will that can be cast in and out from a
> universal type.
>
> It's probably worth reading over the Univ module in Core as well,
> since Univ_map is built on it, and if Univ_map doesn't quite do what
> you want, you can probably built what you need precisely on top of
> Univ.
>
> > Say these modifiers use Wounds.t, Fatigue.t, Ability.Score.t, ... There
> are
> > a
> > lot of types, which mostly have a limited scope (their own module and a
> few
> > others). Wouldn't it be a problem to have all types brought into this one
> > module, which every other module also becomes dependent on? Maybe it just
> > feels like a problem but it's just an aesthetic -- Would you do this? A
> few
> > hundred keys involving types from half the modules of the codebase?
> >
> >
> > I'm trying to use these "modifiers" for code organisation -- declaring
> > snippets of functionality (all of signature 'a -> 'a... to return
> modified
> > input) in a lightweight manner, which can be applied elsewhere.
> >
> > For example, the Virtue module can add a lot of modifers to an entity
> (UID).
> > Say one entity has virtues of Agility, Inspirational, and Sun-cyclic
> Magic,
> > which each adding a few modifier functions keyed to various contexts
> > (sun-cyclic magic: "Casting" is +3 while the sun is up). The associated
> > modifiers would be picked up in code spread throughout the application.
> > Rules
> > for combat, spellcasting, even character dialog...
> >
> > Rather than having character dialog checking for "does he have this
> virtue,
> > or
> > that one? How about this ability? Spell-effects? Reputations? ..." I
> want to
> > apply all appropriate/active modifiers for entity and situation which
> come
> > from other rules. So, dialog code might have a current_value, then...
> > eg.
> >   let modified_value = apply_modifiers_for_context entity `CharmRoll
> > current_value
> >
> > There is a lot of work on my project which I've been avoiding because the
> > direct approach is building hairy nests of checks which call out to code
> > everywhere... effectively splitting logic between the point of origin of
> a
> > rule, and the point of application of it. I'd rather declare the
> individual
> > rules, each in one piece, and "magically" apply the aggregate of rules.
> >
> >
> > In a way, what I'm looking for is having a grand-central lookup, which
> > *trusts* that I'm using the right keys at the right time (where the keys
> are
> > purely symbolic with no type info)... but it would be nice if once the
> whole
> > program is compiled it could identify whether that trust was broken
> > afterall.
> > A bit of a pipe-dream, and maybe even flawed logic. :)
> >
> > It might sound like I'm being too picky or even whiney... that declaring
> > keys
> > throughout the code is unacceptable, or having a file dependent on all
> types
> > is problematic... maybe I am? The first seems disorganised and adds a
> > mental burden to deciding and knowing where keys live; the second is a
> > problem, isn't it?
> >
> > Dynamic languages can do what I want at the cost of typesafety. So I
> might
> > just prefer to make that same tradeoff for one mechanism in my code...
> > "famous
> > last words"? I hope not. I hope it just works and I don't have nightmares
> > about lurking segfaults. :)
> >
> >
> > On Thu, Apr 4, 2013 at 3:04 AM, David House <dhouse@janestreet.com>
> wrote:
> >>
> >> I don't quite understand the problem. Here's an example of how one
> >> might use univ_map:
> >>
> >> open Core.Std
> >>
> >> module Keys : sig
> >>   val recovery : int Univ_map.Key.t
> >>   val resist_pain : float  Univ_map.Key.t
> >> end = struct
> >>   let recovery = Univ_key.Key.create "recovery" Int.sexp_of_t
> >>   let resist_pain = Univ_key.Key.create "resist_pain" Float.sexp_of_t
> >> end
> >>
> >> (In practice this might be two files: keys.ml with the implementation
> >> and keys.mli with the signature.) You can then add things as follows:
> >>
> >> let add map ~key ~data = Univ_map.add_exn map key data in
> >> let map =
> >>   Univ_map.empty
> >>   |> add ~key:Keys.recovery ~data:4
> >>   |> add ~key:Keys.resist_pain ~data:10.
> >> in
> >> ...
> >>
> >> On 4 April 2013 09:37, Anthony Tavener <anthony.tavener@gmail.com>
> wrote:
> >> > Thank-you for the advice and pointers, folks...
> >> >
> >> > Well, the common problem is still the same one I've been struggling
> >> > with:
> >> > "creating keys", and having to access them.
> >> >
> >> > I can't create keys "type-free" in a common module. As I figured...
> >> > having
> >> > "modifier.ml" with a bunch of Key.create will have monomorphic types
> >> > which
> >> > can't be resolved since with no usage in that module to make the type
> >> > concrete. I had a nagging feeling I'd need a "whole-program"
> compiler...
> >> >
> >> > Instead I'd have to create keys in modules where they are used... but
> >> > then I
> >> > might have a mess of keys like Wounds.recovery, Combat.resist_pain,
> ...
> >> > the
> >> > problem being that only a fraction of these keys actually make sense
> >> > being
> >> > associated to a particular module, and it gets confusing to know which
> >> > (of
> >> > several candidates) I decided to stash them into. This was the
> >> > attraction to
> >> > polymorphic variants (which I rarely use) -- they give a pre-ordained
> >> > unique
> >> > ID based on a simple name... no declaration, and no module prefixing,
> >> > which
> >> > seems important to me for this case.
> >> >
> >> > Note that I have a "database" of tables with different types
> >> > (implemented by
> >> > first-class modules!), and it works great for the bulk of my
> game-state,
> >> > but
> >> > each table is well-populated and heavily used in consistent manner.
> >> > These
> >> > modifiers though... they're a bit like ad-hoc message passing, where I
> >> > can
> >> > submit any message and anywhere else add a snippet of code to
> interpret
> >> > it
> >> > (not that I have any of that going on, otherwise it might hold the
> >> > solution!).
> >> >
> >> >
> >> >
> >> > On Thu, Apr 4, 2013 at 1:38 AM, Raphaël Proust <raphlalou@gmail.com>
> >> > wrote:
> >> >>
> >> >> On Thu, Apr 4, 2013 at 1:45 AM, Anthony Tavener
> >> >> <anthony.tavener@gmail.com> wrote:
> >> >> > […]
> >> >>
> >> >> And yet-another-solution, Ocsigen's Polytable:
> >> >> http://ocsigen.org/ocsigenserver/api/Polytables
> >> >>
> >> >>
> >> >> Cheers,
> >> >> --
> >> >> ______________
> >> >> Raphaël Proust
> >> >
> >> >
> >
> >
>

[-- Attachment #2: Type: text/html, Size: 14325 bytes --]

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [Caml-list] Heterogeneous dictionary
  2013-04-05 18:27           ` Anthony Tavener
@ 2013-04-05 18:51             ` Yaron Minsky
  2013-04-05 19:55               ` Anthony Tavener
  0 siblings, 1 reply; 17+ messages in thread
From: Yaron Minsky @ 2013-04-05 18:51 UTC (permalink / raw)
  To: Anthony Tavener; +Cc: caml-list

On Fri, Apr 5, 2013 at 2:27 PM, Anthony Tavener
<anthony.tavener@gmail.com> wrote:
>> Sure, but there's nothing that requires these to be stored together.
>> They can be scattered to the four winds, and yet all used to keep
>> things in the same Univ_map.t.
>
> I was working with a universal type, but that was exactly the
> problem I encountered: I need to create the keys and hold them
> somewhere. My original post might have been unclear, sorry. This is
> what I meant by having to pre-create the inj/proj pair and house
> them somewhere... where a single file would create a bottleneck of
> types, or scattered becomes a "mess". Scattered would prove
> confusing I think... with hundreds of keys that have no sensible
> "home" module. Well, some might make sense, but most of these keys
> are interstitial -- between modules, somewhat like messages. I was
> trying to map out where various keys would live and it wasn't
> obvious and would continue to be unclear when I wanted to use a
> key. There would be cognitive burden of deciding home modules for
> things which don't fit into the modular namespace.

My experience with this kind of design is that this isn't that much of
a problem.  You can create multiple modules that house keys for
different concerns.  Indeed, in such designs I've historically created
modules with typeful interfaces that back-end on such keys, but simply
expose a typeful way of getting access to the properties in question,
which I think turns out quite prettily.

> So, a universal type with "keys" does solve the problem, for some
> definition of solved. My concern is that the solution is too
> cumbersome and confusing in this use-case. Very much like arguments
> for polymorphic variants versus variants. Unfortunately I don't see
> any way to "embed type" in a polymorphic variant (I did check
> whether hashes could match between different function
> implementations of same type-signature... which was kind of silly
> because I'm pretty sure the function address would be used in the
> hashvalue). Although I imagine types do have hashvalues at some
> point in the compiler!

Again, If you create wrapper modules for accessing and working with
these properties, I think everything will work smoothly.  Indeed, if
you have a module T for a given type of thing to be stored in one of
these maps, you can build your typeful accessors for T.t into module
T.  You just need to follow the design pattern of having one module
per type you define.

> Another (failed?) possibility I mentioned as a pipe-dream: if "keys"
> could be left open "to trust", and then verified that all trusted
> usages lined up at link-time. After you're first reply (Yaron), I
> thought for a moment that monomorphic types might work like that --
> resolved at link time. Of course, they're not, as a test quickly
> confirmed. :( But... that's why I asked the wise body of OCamlers if
> you have ideas -- I don't have a complete grasp of the language and
> might be missing something or have a false assumption. It's a
> complex type-system! I like it a lot though.
>
> Thinking more about this, and formulating these replies, I've
> realized there's a common idiom in game development -- and maybe
> software in general?  It's use of string-hashes to create flexible
> associations... from code to code, or code to data (I think that's
> how it starts... you need to share "IDs" between code and data --
> and then the technique spreads).  Messages, names of special points
> in artwork (eg "primary-grip"), effects, things accessible by
> script...  But with such extensive usage, you need tools to verify
> correct usage as much as possible. C, of course, provides few
> guarantees of anything, so you write your own tools. OCaml is
> tantalizing with its rich typesystem -- and polymorphic variants are
> like built-in string-hash support. So I kept trying to figure out a
> way to get OCaml to do the heavy lifting... for idioms I might be
> unreasonably stuck on. ;)

Maybe.  My intuition is that the design pattern you're talking about
is a good one, and really can be made to work well in OCaml.

y

> On Fri, Apr 5, 2013 at 10:37 AM, Yaron Minsky <yminsky@janestreet.com>
> wrote:
>>
>> On Thu, Apr 4, 2013 at 2:48 PM, Anthony Tavener
>> <anthony.tavener@gmail.com> wrote:
>> > The problem here...
>> >
>> >   module Keys : sig
>> >     val recovery : int Univ_map.Key.t
>> >     val resist_pain : float  Univ_map.Key.t
>> >     ...
>> >
>> > Would be that Keys would now have dependence on types spanning the
>> > codebase.
>>
>> Sure, but there's nothing that requires these to be stored together.
>> They can be scattered to the four winds, and yet all used to keep
>> things in the same Univ_map.t.
>>
>> It's honestly very much like using a dynamic language, where you get
>> to declare new items at will that can be cast in and out from a
>> universal type.
>>
>> It's probably worth reading over the Univ module in Core as well,
>> since Univ_map is built on it, and if Univ_map doesn't quite do what
>> you want, you can probably built what you need precisely on top of
>> Univ.
>>
>> > Say these modifiers use Wounds.t, Fatigue.t, Ability.Score.t, ... There
>> > are
>> > a
>> > lot of types, which mostly have a limited scope (their own module and a
>> > few
>> > others). Wouldn't it be a problem to have all types brought into this
>> > one
>> > module, which every other module also becomes dependent on? Maybe it
>> > just
>> > feels like a problem but it's just an aesthetic -- Would you do this? A
>> > few
>> > hundred keys involving types from half the modules of the codebase?
>> >
>> >
>> > I'm trying to use these "modifiers" for code organisation -- declaring
>> > snippets of functionality (all of signature 'a -> 'a... to return
>> > modified
>> > input) in a lightweight manner, which can be applied elsewhere.
>> >
>> > For example, the Virtue module can add a lot of modifers to an entity
>> > (UID).
>> > Say one entity has virtues of Agility, Inspirational, and Sun-cyclic
>> > Magic,
>> > which each adding a few modifier functions keyed to various contexts
>> > (sun-cyclic magic: "Casting" is +3 while the sun is up). The associated
>> > modifiers would be picked up in code spread throughout the application.
>> > Rules
>> > for combat, spellcasting, even character dialog...
>> >
>> > Rather than having character dialog checking for "does he have this
>> > virtue,
>> > or
>> > that one? How about this ability? Spell-effects? Reputations? ..." I
>> > want to
>> > apply all appropriate/active modifiers for entity and situation which
>> > come
>> > from other rules. So, dialog code might have a current_value, then...
>> > eg.
>> >   let modified_value = apply_modifiers_for_context entity `CharmRoll
>> > current_value
>> >
>> > There is a lot of work on my project which I've been avoiding because
>> > the
>> > direct approach is building hairy nests of checks which call out to code
>> > everywhere... effectively splitting logic between the point of origin of
>> > a
>> > rule, and the point of application of it. I'd rather declare the
>> > individual
>> > rules, each in one piece, and "magically" apply the aggregate of rules.
>> >
>> >
>> > In a way, what I'm looking for is having a grand-central lookup, which
>> > *trusts* that I'm using the right keys at the right time (where the keys
>> > are
>> > purely symbolic with no type info)... but it would be nice if once the
>> > whole
>> > program is compiled it could identify whether that trust was broken
>> > afterall.
>> > A bit of a pipe-dream, and maybe even flawed logic. :)
>> >
>> > It might sound like I'm being too picky or even whiney... that declaring
>> > keys
>> > throughout the code is unacceptable, or having a file dependent on all
>> > types
>> > is problematic... maybe I am? The first seems disorganised and adds a
>> > mental burden to deciding and knowing where keys live; the second is a
>> > problem, isn't it?
>> >
>> > Dynamic languages can do what I want at the cost of typesafety. So I
>> > might
>> > just prefer to make that same tradeoff for one mechanism in my code...
>> > "famous
>> > last words"? I hope not. I hope it just works and I don't have
>> > nightmares
>> > about lurking segfaults. :)
>> >
>> >
>> > On Thu, Apr 4, 2013 at 3:04 AM, David House <dhouse@janestreet.com>
>> > wrote:
>> >>
>> >> I don't quite understand the problem. Here's an example of how one
>> >> might use univ_map:
>> >>
>> >> open Core.Std
>> >>
>> >> module Keys : sig
>> >>   val recovery : int Univ_map.Key.t
>> >>   val resist_pain : float  Univ_map.Key.t
>> >> end = struct
>> >>   let recovery = Univ_key.Key.create "recovery" Int.sexp_of_t
>> >>   let resist_pain = Univ_key.Key.create "resist_pain" Float.sexp_of_t
>> >> end
>> >>
>> >> (In practice this might be two files: keys.ml with the implementation
>> >> and keys.mli with the signature.) You can then add things as follows:
>> >>
>> >> let add map ~key ~data = Univ_map.add_exn map key data in
>> >> let map =
>> >>   Univ_map.empty
>> >>   |> add ~key:Keys.recovery ~data:4
>> >>   |> add ~key:Keys.resist_pain ~data:10.
>> >> in
>> >> ...
>> >>
>> >> On 4 April 2013 09:37, Anthony Tavener <anthony.tavener@gmail.com>
>> >> wrote:
>> >> > Thank-you for the advice and pointers, folks...
>> >> >
>> >> > Well, the common problem is still the same one I've been struggling
>> >> > with:
>> >> > "creating keys", and having to access them.
>> >> >
>> >> > I can't create keys "type-free" in a common module. As I figured...
>> >> > having
>> >> > "modifier.ml" with a bunch of Key.create will have monomorphic types
>> >> > which
>> >> > can't be resolved since with no usage in that module to make the type
>> >> > concrete. I had a nagging feeling I'd need a "whole-program"
>> >> > compiler...
>> >> >
>> >> > Instead I'd have to create keys in modules where they are used... but
>> >> > then I
>> >> > might have a mess of keys like Wounds.recovery, Combat.resist_pain,
>> >> > ...
>> >> > the
>> >> > problem being that only a fraction of these keys actually make sense
>> >> > being
>> >> > associated to a particular module, and it gets confusing to know
>> >> > which
>> >> > (of
>> >> > several candidates) I decided to stash them into. This was the
>> >> > attraction to
>> >> > polymorphic variants (which I rarely use) -- they give a pre-ordained
>> >> > unique
>> >> > ID based on a simple name... no declaration, and no module prefixing,
>> >> > which
>> >> > seems important to me for this case.
>> >> >
>> >> > Note that I have a "database" of tables with different types
>> >> > (implemented by
>> >> > first-class modules!), and it works great for the bulk of my
>> >> > game-state,
>> >> > but
>> >> > each table is well-populated and heavily used in consistent manner.
>> >> > These
>> >> > modifiers though... they're a bit like ad-hoc message passing, where
>> >> > I
>> >> > can
>> >> > submit any message and anywhere else add a snippet of code to
>> >> > interpret
>> >> > it
>> >> > (not that I have any of that going on, otherwise it might hold the
>> >> > solution!).
>> >> >
>> >> >
>> >> >
>> >> > On Thu, Apr 4, 2013 at 1:38 AM, Raphaël Proust <raphlalou@gmail.com>
>> >> > wrote:
>> >> >>
>> >> >> On Thu, Apr 4, 2013 at 1:45 AM, Anthony Tavener
>> >> >> <anthony.tavener@gmail.com> wrote:
>> >> >> > […]
>> >> >>
>> >> >> And yet-another-solution, Ocsigen's Polytable:
>> >> >> http://ocsigen.org/ocsigenserver/api/Polytables
>> >> >>
>> >> >>
>> >> >> Cheers,
>> >> >> --
>> >> >> ______________
>> >> >> Raphaël Proust
>> >> >
>> >> >
>> >
>> >
>
>

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [Caml-list] Heterogeneous dictionary
  2013-04-05 18:51             ` Yaron Minsky
@ 2013-04-05 19:55               ` Anthony Tavener
  2013-04-05 20:03                 ` Yaron Minsky
  0 siblings, 1 reply; 17+ messages in thread
From: Anthony Tavener @ 2013-04-05 19:55 UTC (permalink / raw)
  To: Yaron Minsky; +Cc: caml-list

[-- Attachment #1: Type: text/plain, Size: 13469 bytes --]

Hmm... that is some food for thought. I wasn't really considering
the creation of modules which might only hold a few keys.
Sometimes we overlook simple things. :) You've convinced me
enough to work with it and see how it fits -- it sounds like you've
had similar cases, and turning out "prettily" is appealing.

I do have a pattern of Module.t. I remember thinking that was
an odd idiom, at first, and used an "appropriate" full name. Once
I really started using modules, and especially functors, I saw the
light. Is there a design patterns for OCaml, somewhere? :)

Thank-you for wading through my walls of text and still offering
advice, Yaron!


On Fri, Apr 5, 2013 at 12:51 PM, Yaron Minsky <yminsky@janestreet.com>wrote:

> On Fri, Apr 5, 2013 at 2:27 PM, Anthony Tavener
> <anthony.tavener@gmail.com> wrote:
> >> Sure, but there's nothing that requires these to be stored together.
> >> They can be scattered to the four winds, and yet all used to keep
> >> things in the same Univ_map.t.
> >
> > I was working with a universal type, but that was exactly the
> > problem I encountered: I need to create the keys and hold them
> > somewhere. My original post might have been unclear, sorry. This is
> > what I meant by having to pre-create the inj/proj pair and house
> > them somewhere... where a single file would create a bottleneck of
> > types, or scattered becomes a "mess". Scattered would prove
> > confusing I think... with hundreds of keys that have no sensible
> > "home" module. Well, some might make sense, but most of these keys
> > are interstitial -- between modules, somewhat like messages. I was
> > trying to map out where various keys would live and it wasn't
> > obvious and would continue to be unclear when I wanted to use a
> > key. There would be cognitive burden of deciding home modules for
> > things which don't fit into the modular namespace.
>
> My experience with this kind of design is that this isn't that much of
> a problem.  You can create multiple modules that house keys for
> different concerns.  Indeed, in such designs I've historically created
> modules with typeful interfaces that back-end on such keys, but simply
> expose a typeful way of getting access to the properties in question,
> which I think turns out quite prettily.
>
> > So, a universal type with "keys" does solve the problem, for some
> > definition of solved. My concern is that the solution is too
> > cumbersome and confusing in this use-case. Very much like arguments
> > for polymorphic variants versus variants. Unfortunately I don't see
> > any way to "embed type" in a polymorphic variant (I did check
> > whether hashes could match between different function
> > implementations of same type-signature... which was kind of silly
> > because I'm pretty sure the function address would be used in the
> > hashvalue). Although I imagine types do have hashvalues at some
> > point in the compiler!
>
> Again, If you create wrapper modules for accessing and working with
> these properties, I think everything will work smoothly.  Indeed, if
> you have a module T for a given type of thing to be stored in one of
> these maps, you can build your typeful accessors for T.t into module
> T.  You just need to follow the design pattern of having one module
> per type you define.
>
> > Another (failed?) possibility I mentioned as a pipe-dream: if "keys"
> > could be left open "to trust", and then verified that all trusted
> > usages lined up at link-time. After you're first reply (Yaron), I
> > thought for a moment that monomorphic types might work like that --
> > resolved at link time. Of course, they're not, as a test quickly
> > confirmed. :( But... that's why I asked the wise body of OCamlers if
> > you have ideas -- I don't have a complete grasp of the language and
> > might be missing something or have a false assumption. It's a
> > complex type-system! I like it a lot though.
> >
> > Thinking more about this, and formulating these replies, I've
> > realized there's a common idiom in game development -- and maybe
> > software in general?  It's use of string-hashes to create flexible
> > associations... from code to code, or code to data (I think that's
> > how it starts... you need to share "IDs" between code and data --
> > and then the technique spreads).  Messages, names of special points
> > in artwork (eg "primary-grip"), effects, things accessible by
> > script...  But with such extensive usage, you need tools to verify
> > correct usage as much as possible. C, of course, provides few
> > guarantees of anything, so you write your own tools. OCaml is
> > tantalizing with its rich typesystem -- and polymorphic variants are
> > like built-in string-hash support. So I kept trying to figure out a
> > way to get OCaml to do the heavy lifting... for idioms I might be
> > unreasonably stuck on. ;)
>
> Maybe.  My intuition is that the design pattern you're talking about
> is a good one, and really can be made to work well in OCaml.
>
> y
>
> > On Fri, Apr 5, 2013 at 10:37 AM, Yaron Minsky <yminsky@janestreet.com>
> > wrote:
> >>
> >> On Thu, Apr 4, 2013 at 2:48 PM, Anthony Tavener
> >> <anthony.tavener@gmail.com> wrote:
> >> > The problem here...
> >> >
> >> >   module Keys : sig
> >> >     val recovery : int Univ_map.Key.t
> >> >     val resist_pain : float  Univ_map.Key.t
> >> >     ...
> >> >
> >> > Would be that Keys would now have dependence on types spanning the
> >> > codebase.
> >>
> >> Sure, but there's nothing that requires these to be stored together.
> >> They can be scattered to the four winds, and yet all used to keep
> >> things in the same Univ_map.t.
> >>
> >> It's honestly very much like using a dynamic language, where you get
> >> to declare new items at will that can be cast in and out from a
> >> universal type.
> >>
> >> It's probably worth reading over the Univ module in Core as well,
> >> since Univ_map is built on it, and if Univ_map doesn't quite do what
> >> you want, you can probably built what you need precisely on top of
> >> Univ.
> >>
> >> > Say these modifiers use Wounds.t, Fatigue.t, Ability.Score.t, ...
> There
> >> > are
> >> > a
> >> > lot of types, which mostly have a limited scope (their own module and
> a
> >> > few
> >> > others). Wouldn't it be a problem to have all types brought into this
> >> > one
> >> > module, which every other module also becomes dependent on? Maybe it
> >> > just
> >> > feels like a problem but it's just an aesthetic -- Would you do this?
> A
> >> > few
> >> > hundred keys involving types from half the modules of the codebase?
> >> >
> >> >
> >> > I'm trying to use these "modifiers" for code organisation -- declaring
> >> > snippets of functionality (all of signature 'a -> 'a... to return
> >> > modified
> >> > input) in a lightweight manner, which can be applied elsewhere.
> >> >
> >> > For example, the Virtue module can add a lot of modifers to an entity
> >> > (UID).
> >> > Say one entity has virtues of Agility, Inspirational, and Sun-cyclic
> >> > Magic,
> >> > which each adding a few modifier functions keyed to various contexts
> >> > (sun-cyclic magic: "Casting" is +3 while the sun is up). The
> associated
> >> > modifiers would be picked up in code spread throughout the
> application.
> >> > Rules
> >> > for combat, spellcasting, even character dialog...
> >> >
> >> > Rather than having character dialog checking for "does he have this
> >> > virtue,
> >> > or
> >> > that one? How about this ability? Spell-effects? Reputations? ..." I
> >> > want to
> >> > apply all appropriate/active modifiers for entity and situation which
> >> > come
> >> > from other rules. So, dialog code might have a current_value, then...
> >> > eg.
> >> >   let modified_value = apply_modifiers_for_context entity `CharmRoll
> >> > current_value
> >> >
> >> > There is a lot of work on my project which I've been avoiding because
> >> > the
> >> > direct approach is building hairy nests of checks which call out to
> code
> >> > everywhere... effectively splitting logic between the point of origin
> of
> >> > a
> >> > rule, and the point of application of it. I'd rather declare the
> >> > individual
> >> > rules, each in one piece, and "magically" apply the aggregate of
> rules.
> >> >
> >> >
> >> > In a way, what I'm looking for is having a grand-central lookup, which
> >> > *trusts* that I'm using the right keys at the right time (where the
> keys
> >> > are
> >> > purely symbolic with no type info)... but it would be nice if once the
> >> > whole
> >> > program is compiled it could identify whether that trust was broken
> >> > afterall.
> >> > A bit of a pipe-dream, and maybe even flawed logic. :)
> >> >
> >> > It might sound like I'm being too picky or even whiney... that
> declaring
> >> > keys
> >> > throughout the code is unacceptable, or having a file dependent on all
> >> > types
> >> > is problematic... maybe I am? The first seems disorganised and adds a
> >> > mental burden to deciding and knowing where keys live; the second is a
> >> > problem, isn't it?
> >> >
> >> > Dynamic languages can do what I want at the cost of typesafety. So I
> >> > might
> >> > just prefer to make that same tradeoff for one mechanism in my code...
> >> > "famous
> >> > last words"? I hope not. I hope it just works and I don't have
> >> > nightmares
> >> > about lurking segfaults. :)
> >> >
> >> >
> >> > On Thu, Apr 4, 2013 at 3:04 AM, David House <dhouse@janestreet.com>
> >> > wrote:
> >> >>
> >> >> I don't quite understand the problem. Here's an example of how one
> >> >> might use univ_map:
> >> >>
> >> >> open Core.Std
> >> >>
> >> >> module Keys : sig
> >> >>   val recovery : int Univ_map.Key.t
> >> >>   val resist_pain : float  Univ_map.Key.t
> >> >> end = struct
> >> >>   let recovery = Univ_key.Key.create "recovery" Int.sexp_of_t
> >> >>   let resist_pain = Univ_key.Key.create "resist_pain" Float.sexp_of_t
> >> >> end
> >> >>
> >> >> (In practice this might be two files: keys.ml with the
> implementation
> >> >> and keys.mli with the signature.) You can then add things as follows:
> >> >>
> >> >> let add map ~key ~data = Univ_map.add_exn map key data in
> >> >> let map =
> >> >>   Univ_map.empty
> >> >>   |> add ~key:Keys.recovery ~data:4
> >> >>   |> add ~key:Keys.resist_pain ~data:10.
> >> >> in
> >> >> ...
> >> >>
> >> >> On 4 April 2013 09:37, Anthony Tavener <anthony.tavener@gmail.com>
> >> >> wrote:
> >> >> > Thank-you for the advice and pointers, folks...
> >> >> >
> >> >> > Well, the common problem is still the same one I've been struggling
> >> >> > with:
> >> >> > "creating keys", and having to access them.
> >> >> >
> >> >> > I can't create keys "type-free" in a common module. As I figured...
> >> >> > having
> >> >> > "modifier.ml" with a bunch of Key.create will have monomorphic
> types
> >> >> > which
> >> >> > can't be resolved since with no usage in that module to make the
> type
> >> >> > concrete. I had a nagging feeling I'd need a "whole-program"
> >> >> > compiler...
> >> >> >
> >> >> > Instead I'd have to create keys in modules where they are used...
> but
> >> >> > then I
> >> >> > might have a mess of keys like Wounds.recovery, Combat.resist_pain,
> >> >> > ...
> >> >> > the
> >> >> > problem being that only a fraction of these keys actually make
> sense
> >> >> > being
> >> >> > associated to a particular module, and it gets confusing to know
> >> >> > which
> >> >> > (of
> >> >> > several candidates) I decided to stash them into. This was the
> >> >> > attraction to
> >> >> > polymorphic variants (which I rarely use) -- they give a
> pre-ordained
> >> >> > unique
> >> >> > ID based on a simple name... no declaration, and no module
> prefixing,
> >> >> > which
> >> >> > seems important to me for this case.
> >> >> >
> >> >> > Note that I have a "database" of tables with different types
> >> >> > (implemented by
> >> >> > first-class modules!), and it works great for the bulk of my
> >> >> > game-state,
> >> >> > but
> >> >> > each table is well-populated and heavily used in consistent manner.
> >> >> > These
> >> >> > modifiers though... they're a bit like ad-hoc message passing,
> where
> >> >> > I
> >> >> > can
> >> >> > submit any message and anywhere else add a snippet of code to
> >> >> > interpret
> >> >> > it
> >> >> > (not that I have any of that going on, otherwise it might hold the
> >> >> > solution!).
> >> >> >
> >> >> >
> >> >> >
> >> >> > On Thu, Apr 4, 2013 at 1:38 AM, Raphaël Proust <
> raphlalou@gmail.com>
> >> >> > wrote:
> >> >> >>
> >> >> >> On Thu, Apr 4, 2013 at 1:45 AM, Anthony Tavener
> >> >> >> <anthony.tavener@gmail.com> wrote:
> >> >> >> > […]
> >> >> >>
> >> >> >> And yet-another-solution, Ocsigen's Polytable:
> >> >> >> http://ocsigen.org/ocsigenserver/api/Polytables
> >> >> >>
> >> >> >>
> >> >> >> Cheers,
> >> >> >> --
> >> >> >> ______________
> >> >> >> Raphaël Proust
> >> >> >
> >> >> >
> >> >
> >> >
> >
> >
>
> --
> Caml-list mailing list.  Subscription management and archives:
> https://sympa.inria.fr/sympa/arc/caml-list
> Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
> Bug reports: http://caml.inria.fr/bin/caml-bugs
>

[-- Attachment #2: Type: text/html, Size: 18259 bytes --]

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [Caml-list] Heterogeneous dictionary
  2013-04-05 19:55               ` Anthony Tavener
@ 2013-04-05 20:03                 ` Yaron Minsky
  2013-04-05 20:27                   ` Anthony Tavener
  0 siblings, 1 reply; 17+ messages in thread
From: Yaron Minsky @ 2013-04-05 20:03 UTC (permalink / raw)
  To: Anthony Tavener; +Cc: caml-list

On Fri, Apr 5, 2013 at 3:55 PM, Anthony Tavener
<anthony.tavener@gmail.com> wrote:
> Hmm... that is some food for thought. I wasn't really considering
> the creation of modules which might only hold a few keys.
> Sometimes we overlook simple things. :) You've convinced me
> enough to work with it and see how it fits -- it sounds like you've
> had similar cases, and turning out "prettily" is appealing.
>
> I do have a pattern of Module.t. I remember thinking that was
> an odd idiom, at first, and used an "appropriate" full name. Once
> I really started using modules, and especially functors, I saw the
> light. Is there a design patterns for OCaml, somewhere? :)

Jason, Anil and I are working Real World OCaml.  I'm hoping that will
have some utility for this purpose.

> Thank-you for wading through my walls of text and still offering
> advice, Yaron!
>
>
> On Fri, Apr 5, 2013 at 12:51 PM, Yaron Minsky <yminsky@janestreet.com>
> wrote:
>>
>> On Fri, Apr 5, 2013 at 2:27 PM, Anthony Tavener
>> <anthony.tavener@gmail.com> wrote:
>> >> Sure, but there's nothing that requires these to be stored together.
>> >> They can be scattered to the four winds, and yet all used to keep
>> >> things in the same Univ_map.t.
>> >
>> > I was working with a universal type, but that was exactly the
>> > problem I encountered: I need to create the keys and hold them
>> > somewhere. My original post might have been unclear, sorry. This is
>> > what I meant by having to pre-create the inj/proj pair and house
>> > them somewhere... where a single file would create a bottleneck of
>> > types, or scattered becomes a "mess". Scattered would prove
>> > confusing I think... with hundreds of keys that have no sensible
>> > "home" module. Well, some might make sense, but most of these keys
>> > are interstitial -- between modules, somewhat like messages. I was
>> > trying to map out where various keys would live and it wasn't
>> > obvious and would continue to be unclear when I wanted to use a
>> > key. There would be cognitive burden of deciding home modules for
>> > things which don't fit into the modular namespace.
>>
>> My experience with this kind of design is that this isn't that much of
>> a problem.  You can create multiple modules that house keys for
>> different concerns.  Indeed, in such designs I've historically created
>> modules with typeful interfaces that back-end on such keys, but simply
>> expose a typeful way of getting access to the properties in question,
>> which I think turns out quite prettily.
>>
>> > So, a universal type with "keys" does solve the problem, for some
>> > definition of solved. My concern is that the solution is too
>> > cumbersome and confusing in this use-case. Very much like arguments
>> > for polymorphic variants versus variants. Unfortunately I don't see
>> > any way to "embed type" in a polymorphic variant (I did check
>> > whether hashes could match between different function
>> > implementations of same type-signature... which was kind of silly
>> > because I'm pretty sure the function address would be used in the
>> > hashvalue). Although I imagine types do have hashvalues at some
>> > point in the compiler!
>>
>> Again, If you create wrapper modules for accessing and working with
>> these properties, I think everything will work smoothly.  Indeed, if
>> you have a module T for a given type of thing to be stored in one of
>> these maps, you can build your typeful accessors for T.t into module
>> T.  You just need to follow the design pattern of having one module
>> per type you define.
>>
>> > Another (failed?) possibility I mentioned as a pipe-dream: if "keys"
>> > could be left open "to trust", and then verified that all trusted
>> > usages lined up at link-time. After you're first reply (Yaron), I
>> > thought for a moment that monomorphic types might work like that --
>> > resolved at link time. Of course, they're not, as a test quickly
>> > confirmed. :( But... that's why I asked the wise body of OCamlers if
>> > you have ideas -- I don't have a complete grasp of the language and
>> > might be missing something or have a false assumption. It's a
>> > complex type-system! I like it a lot though.
>> >
>> > Thinking more about this, and formulating these replies, I've
>> > realized there's a common idiom in game development -- and maybe
>> > software in general?  It's use of string-hashes to create flexible
>> > associations... from code to code, or code to data (I think that's
>> > how it starts... you need to share "IDs" between code and data --
>> > and then the technique spreads).  Messages, names of special points
>> > in artwork (eg "primary-grip"), effects, things accessible by
>> > script...  But with such extensive usage, you need tools to verify
>> > correct usage as much as possible. C, of course, provides few
>> > guarantees of anything, so you write your own tools. OCaml is
>> > tantalizing with its rich typesystem -- and polymorphic variants are
>> > like built-in string-hash support. So I kept trying to figure out a
>> > way to get OCaml to do the heavy lifting... for idioms I might be
>> > unreasonably stuck on. ;)
>>
>> Maybe.  My intuition is that the design pattern you're talking about
>> is a good one, and really can be made to work well in OCaml.
>>
>> y
>>
>> > On Fri, Apr 5, 2013 at 10:37 AM, Yaron Minsky <yminsky@janestreet.com>
>> > wrote:
>> >>
>> >> On Thu, Apr 4, 2013 at 2:48 PM, Anthony Tavener
>> >> <anthony.tavener@gmail.com> wrote:
>> >> > The problem here...
>> >> >
>> >> >   module Keys : sig
>> >> >     val recovery : int Univ_map.Key.t
>> >> >     val resist_pain : float  Univ_map.Key.t
>> >> >     ...
>> >> >
>> >> > Would be that Keys would now have dependence on types spanning the
>> >> > codebase.
>> >>
>> >> Sure, but there's nothing that requires these to be stored together.
>> >> They can be scattered to the four winds, and yet all used to keep
>> >> things in the same Univ_map.t.
>> >>
>> >> It's honestly very much like using a dynamic language, where you get
>> >> to declare new items at will that can be cast in and out from a
>> >> universal type.
>> >>
>> >> It's probably worth reading over the Univ module in Core as well,
>> >> since Univ_map is built on it, and if Univ_map doesn't quite do what
>> >> you want, you can probably built what you need precisely on top of
>> >> Univ.
>> >>
>> >> > Say these modifiers use Wounds.t, Fatigue.t, Ability.Score.t, ...
>> >> > There
>> >> > are
>> >> > a
>> >> > lot of types, which mostly have a limited scope (their own module and
>> >> > a
>> >> > few
>> >> > others). Wouldn't it be a problem to have all types brought into this
>> >> > one
>> >> > module, which every other module also becomes dependent on? Maybe it
>> >> > just
>> >> > feels like a problem but it's just an aesthetic -- Would you do this?
>> >> > A
>> >> > few
>> >> > hundred keys involving types from half the modules of the codebase?
>> >> >
>> >> >
>> >> > I'm trying to use these "modifiers" for code organisation --
>> >> > declaring
>> >> > snippets of functionality (all of signature 'a -> 'a... to return
>> >> > modified
>> >> > input) in a lightweight manner, which can be applied elsewhere.
>> >> >
>> >> > For example, the Virtue module can add a lot of modifers to an entity
>> >> > (UID).
>> >> > Say one entity has virtues of Agility, Inspirational, and Sun-cyclic
>> >> > Magic,
>> >> > which each adding a few modifier functions keyed to various contexts
>> >> > (sun-cyclic magic: "Casting" is +3 while the sun is up). The
>> >> > associated
>> >> > modifiers would be picked up in code spread throughout the
>> >> > application.
>> >> > Rules
>> >> > for combat, spellcasting, even character dialog...
>> >> >
>> >> > Rather than having character dialog checking for "does he have this
>> >> > virtue,
>> >> > or
>> >> > that one? How about this ability? Spell-effects? Reputations? ..." I
>> >> > want to
>> >> > apply all appropriate/active modifiers for entity and situation which
>> >> > come
>> >> > from other rules. So, dialog code might have a current_value, then...
>> >> > eg.
>> >> >   let modified_value = apply_modifiers_for_context entity `CharmRoll
>> >> > current_value
>> >> >
>> >> > There is a lot of work on my project which I've been avoiding because
>> >> > the
>> >> > direct approach is building hairy nests of checks which call out to
>> >> > code
>> >> > everywhere... effectively splitting logic between the point of origin
>> >> > of
>> >> > a
>> >> > rule, and the point of application of it. I'd rather declare the
>> >> > individual
>> >> > rules, each in one piece, and "magically" apply the aggregate of
>> >> > rules.
>> >> >
>> >> >
>> >> > In a way, what I'm looking for is having a grand-central lookup,
>> >> > which
>> >> > *trusts* that I'm using the right keys at the right time (where the
>> >> > keys
>> >> > are
>> >> > purely symbolic with no type info)... but it would be nice if once
>> >> > the
>> >> > whole
>> >> > program is compiled it could identify whether that trust was broken
>> >> > afterall.
>> >> > A bit of a pipe-dream, and maybe even flawed logic. :)
>> >> >
>> >> > It might sound like I'm being too picky or even whiney... that
>> >> > declaring
>> >> > keys
>> >> > throughout the code is unacceptable, or having a file dependent on
>> >> > all
>> >> > types
>> >> > is problematic... maybe I am? The first seems disorganised and adds a
>> >> > mental burden to deciding and knowing where keys live; the second is
>> >> > a
>> >> > problem, isn't it?
>> >> >
>> >> > Dynamic languages can do what I want at the cost of typesafety. So I
>> >> > might
>> >> > just prefer to make that same tradeoff for one mechanism in my
>> >> > code...
>> >> > "famous
>> >> > last words"? I hope not. I hope it just works and I don't have
>> >> > nightmares
>> >> > about lurking segfaults. :)
>> >> >
>> >> >
>> >> > On Thu, Apr 4, 2013 at 3:04 AM, David House <dhouse@janestreet.com>
>> >> > wrote:
>> >> >>
>> >> >> I don't quite understand the problem. Here's an example of how one
>> >> >> might use univ_map:
>> >> >>
>> >> >> open Core.Std
>> >> >>
>> >> >> module Keys : sig
>> >> >>   val recovery : int Univ_map.Key.t
>> >> >>   val resist_pain : float  Univ_map.Key.t
>> >> >> end = struct
>> >> >>   let recovery = Univ_key.Key.create "recovery" Int.sexp_of_t
>> >> >>   let resist_pain = Univ_key.Key.create "resist_pain"
>> >> >> Float.sexp_of_t
>> >> >> end
>> >> >>
>> >> >> (In practice this might be two files: keys.ml with the
>> >> >> implementation
>> >> >> and keys.mli with the signature.) You can then add things as
>> >> >> follows:
>> >> >>
>> >> >> let add map ~key ~data = Univ_map.add_exn map key data in
>> >> >> let map =
>> >> >>   Univ_map.empty
>> >> >>   |> add ~key:Keys.recovery ~data:4
>> >> >>   |> add ~key:Keys.resist_pain ~data:10.
>> >> >> in
>> >> >> ...
>> >> >>
>> >> >> On 4 April 2013 09:37, Anthony Tavener <anthony.tavener@gmail.com>
>> >> >> wrote:
>> >> >> > Thank-you for the advice and pointers, folks...
>> >> >> >
>> >> >> > Well, the common problem is still the same one I've been
>> >> >> > struggling
>> >> >> > with:
>> >> >> > "creating keys", and having to access them.
>> >> >> >
>> >> >> > I can't create keys "type-free" in a common module. As I
>> >> >> > figured...
>> >> >> > having
>> >> >> > "modifier.ml" with a bunch of Key.create will have monomorphic
>> >> >> > types
>> >> >> > which
>> >> >> > can't be resolved since with no usage in that module to make the
>> >> >> > type
>> >> >> > concrete. I had a nagging feeling I'd need a "whole-program"
>> >> >> > compiler...
>> >> >> >
>> >> >> > Instead I'd have to create keys in modules where they are used...
>> >> >> > but
>> >> >> > then I
>> >> >> > might have a mess of keys like Wounds.recovery,
>> >> >> > Combat.resist_pain,
>> >> >> > ...
>> >> >> > the
>> >> >> > problem being that only a fraction of these keys actually make
>> >> >> > sense
>> >> >> > being
>> >> >> > associated to a particular module, and it gets confusing to know
>> >> >> > which
>> >> >> > (of
>> >> >> > several candidates) I decided to stash them into. This was the
>> >> >> > attraction to
>> >> >> > polymorphic variants (which I rarely use) -- they give a
>> >> >> > pre-ordained
>> >> >> > unique
>> >> >> > ID based on a simple name... no declaration, and no module
>> >> >> > prefixing,
>> >> >> > which
>> >> >> > seems important to me for this case.
>> >> >> >
>> >> >> > Note that I have a "database" of tables with different types
>> >> >> > (implemented by
>> >> >> > first-class modules!), and it works great for the bulk of my
>> >> >> > game-state,
>> >> >> > but
>> >> >> > each table is well-populated and heavily used in consistent
>> >> >> > manner.
>> >> >> > These
>> >> >> > modifiers though... they're a bit like ad-hoc message passing,
>> >> >> > where
>> >> >> > I
>> >> >> > can
>> >> >> > submit any message and anywhere else add a snippet of code to
>> >> >> > interpret
>> >> >> > it
>> >> >> > (not that I have any of that going on, otherwise it might hold the
>> >> >> > solution!).
>> >> >> >
>> >> >> >
>> >> >> >
>> >> >> > On Thu, Apr 4, 2013 at 1:38 AM, Raphaël Proust
>> >> >> > <raphlalou@gmail.com>
>> >> >> > wrote:
>> >> >> >>
>> >> >> >> On Thu, Apr 4, 2013 at 1:45 AM, Anthony Tavener
>> >> >> >> <anthony.tavener@gmail.com> wrote:
>> >> >> >> > […]
>> >> >> >>
>> >> >> >> And yet-another-solution, Ocsigen's Polytable:
>> >> >> >> http://ocsigen.org/ocsigenserver/api/Polytables
>> >> >> >>
>> >> >> >>
>> >> >> >> Cheers,
>> >> >> >> --
>> >> >> >> ______________
>> >> >> >> Raphaël Proust
>> >> >> >
>> >> >> >
>> >> >
>> >> >
>> >
>> >
>>
>> --
>> Caml-list mailing list.  Subscription management and archives:
>> https://sympa.inria.fr/sympa/arc/caml-list
>> Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
>> Bug reports: http://caml.inria.fr/bin/caml-bugs
>
>

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [Caml-list] Heterogeneous dictionary
  2013-04-05 20:03                 ` Yaron Minsky
@ 2013-04-05 20:27                   ` Anthony Tavener
  2013-04-08  8:33                     ` David House
  0 siblings, 1 reply; 17+ messages in thread
From: Anthony Tavener @ 2013-04-05 20:27 UTC (permalink / raw)
  To: Yaron Minsky; +Cc: caml-list

[-- Attachment #1: Type: text/plain, Size: 400 bytes --]

On Fri, Apr 5, 2013 at 2:03 PM, Yaron Minsky <yminsky@janestreet.com> wrote:
> Jason, Anil and I are working Real World OCaml.  I'm hoping that will
> have some utility for this purpose.

Yes, I look forward to it! I have no local OCaml devs to compare
with and aside from a few blogs there isn't much material. Well,
there are a lot of projects with source to study, but a summary
of ideas is nice.

[-- Attachment #2: Type: text/html, Size: 712 bytes --]

^ permalink raw reply	[flat|nested] 17+ messages in thread

* Re: [Caml-list] Heterogeneous dictionary
  2013-04-05 20:27                   ` Anthony Tavener
@ 2013-04-08  8:33                     ` David House
  0 siblings, 0 replies; 17+ messages in thread
From: David House @ 2013-04-08  8:33 UTC (permalink / raw)
  To: Anthony Tavener; +Cc: Yaron Minsky, caml-list

Hopefully as Jane Street releases more of our code and projects, that
could be a useful set of examples.

On 5 April 2013 21:27, Anthony Tavener <anthony.tavener@gmail.com> wrote:
> On Fri, Apr 5, 2013 at 2:03 PM, Yaron Minsky <yminsky@janestreet.com> wrote:
>> Jason, Anil and I are working Real World OCaml.  I'm hoping that will
>> have some utility for this purpose.
>
> Yes, I look forward to it! I have no local OCaml devs to compare
> with and aside from a few blogs there isn't much material. Well,
> there are a lot of projects with source to study, but a summary
> of ideas is nice.
>

^ permalink raw reply	[flat|nested] 17+ messages in thread

end of thread, other threads:[~2013-04-08  8:33 UTC | newest]

Thread overview: 17+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-04-04  0:45 [Caml-list] Heterogeneous dictionary Anthony Tavener
2013-04-04  1:29 ` Yaron Minsky
2013-04-04  2:18   ` Anthony Tavener
2013-04-04  6:19 ` Martin Jambon
2013-04-04  7:32   ` Alain Frisch
2013-04-04 18:16     ` Martin Jambon
2013-04-04  7:38 ` Raphaël Proust
2013-04-04  8:37   ` Anthony Tavener
2013-04-04  9:04     ` David House
2013-04-04 18:48       ` Anthony Tavener
2013-04-05 16:37         ` Yaron Minsky
2013-04-05 18:27           ` Anthony Tavener
2013-04-05 18:51             ` Yaron Minsky
2013-04-05 19:55               ` Anthony Tavener
2013-04-05 20:03                 ` Yaron Minsky
2013-04-05 20:27                   ` Anthony Tavener
2013-04-08  8:33                     ` David House

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