From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: X-Original-To: caml-list@sympa.inria.fr Delivered-To: caml-list@sympa.inria.fr Received: from mail3-relais-sop.national.inria.fr (mail3-relais-sop.national.inria.fr [192.134.164.104]) by sympa.inria.fr (Postfix) with ESMTPS id 598A17EE51 for ; Fri, 5 Apr 2013 22:03:27 +0200 (CEST) Received-SPF: None (mail3-smtp-sop.national.inria.fr: no sender authenticity information available from domain of yminsky@janestreet.com) identity=pra; client-ip=38.105.200.229; receiver=mail3-smtp-sop.national.inria.fr; envelope-from="yminsky@janestreet.com"; x-sender="yminsky@janestreet.com"; x-conformance=sidf_compatible Received-SPF: Pass (mail3-smtp-sop.national.inria.fr: domain of yminsky@janestreet.com designates 38.105.200.229 as permitted sender) identity=mailfrom; client-ip=38.105.200.229; receiver=mail3-smtp-sop.national.inria.fr; envelope-from="yminsky@janestreet.com"; x-sender="yminsky@janestreet.com"; x-conformance=sidf_compatible; x-record-type="v=spf1" Received-SPF: None (mail3-smtp-sop.national.inria.fr: no sender authenticity information available from domain of postmaster@tot-dmz-mxout1.janestreet.com) identity=helo; client-ip=38.105.200.229; receiver=mail3-smtp-sop.national.inria.fr; envelope-from="yminsky@janestreet.com"; x-sender="postmaster@tot-dmz-mxout1.janestreet.com"; x-conformance=sidf_compatible X-IronPort-Anti-Spam-Filtered: true X-IronPort-Anti-Spam-Result: AiABAB0tX1EmacjlmWdsb2JhbABBCoM8rw+SFoEFHg4BAQEBAQYNCwcUKIIfAQEEAScZAQEsCwEECwsLDQ0MAhMhARIBBQEKEgYTEgmHZwMJBgMJo2aKb4Q7AQVChFIDCoEXiEAGjEmBBhAEgQUzBycCgxeVEYFggSCKUoM5FimESoExHQIHFw X-IPAS-Result: AiABAB0tX1EmacjlmWdsb2JhbABBCoM8rw+SFoEFHg4BAQEBAQYNCwcUKIIfAQEEAScZAQEsCwEECwsLDQ0MAhMhARIBBQEKEgYTEgmHZwMJBgMJo2aKb4Q7AQVChFIDCoEXiEAGjEmBBhAEgQUzBycCgxeVEYFggSCKUoM5FimESoExHQIHFw X-IronPort-AV: E=Sophos;i="4.87,416,1363129200"; d="scan'208";a="9978204" Received: from mx5.janestreet.com (HELO tot-dmz-mxout1.janestreet.com) ([38.105.200.229]) by mail3-smtp-sop.national.inria.fr with ESMTP/TLS/DHE-RSA-AES256-SHA; 05 Apr 2013 22:03:25 +0200 Received: from tot-oib-smtp1.delacy.com ([172.27.22.15] helo=tot-smtp) by tot-dmz-mxout1.janestreet.com with esmtp (Exim 4.76) (envelope-from ) id 1UOCr6-0000G3-4v for caml-list@inria.fr; Fri, 05 Apr 2013 16:03:24 -0400 Received: from tot-dmz-mxgoog1.delacy.com ([172.27.224.14] helo=mxgoog2.janestreet.com) by tot-smtp with esmtps (TLSv1:AES256-SHA:256) (Exim 4.72) (envelope-from ) id 1UOCr6-00044k-47 for caml-list@inria.fr; Fri, 05 Apr 2013 16:03:24 -0400 Received: from mail-wi0-f200.google.com ([209.85.212.200]) by mxgoog2.janestreet.com with esmtp (Exim 4.76) (envelope-from ) id 1UOCr5-0003kv-Tg for caml-list@inria.fr; Fri, 05 Apr 2013 16:03:24 -0400 Received: by mail-wi0-f200.google.com with SMTP id hi18so1422891wib.3 for ; Fri, 05 Apr 2013 13:03:23 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=janestreet.com; s=google; h=x-received:mime-version:x-received:in-reply-to:references:date :message-id:subject:from:to:cc:content-type :content-transfer-encoding; bh=bYbQRUDXRGhbZnUTGtTsCTedzMTHHVmYYrgSGySgFl8=; b=lVWaRmq7nOduaHKgs8s30iz+hVUkg5toersbQcrhZ0Hdf/JlUrVgb9pY+OlgWyeJvZ LNvJ89b0o+kdTv/7IhOL8gIO8hCXrmQpqGYPfbXFA4CYK/EyXEXb63uTQ2mtn6nqSMFr cBwe3amonXy33BufNqFI8cqBg6L8SFD+yO0FQ= X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=x-received:mime-version:x-received:in-reply-to:references:date :message-id:subject:from:to:cc:content-type :content-transfer-encoding:x-gm-message-state; bh=bYbQRUDXRGhbZnUTGtTsCTedzMTHHVmYYrgSGySgFl8=; b=l+oOupRSvSE0PqJzWSPRK4+iVcFHbAqvJU68tejkUlXJrMBsBJ5FzJ+4UB7pRr3XKe iNRs3cUCuCDck8UJymD3UeqB/OeNbP1JIFG6QITboChVpUEPe4iaOCNx0vaZAPaILcKP I7EF5mzdZFFAf4OR3rLyqIgUK6Qi6Df8MhHsSBXGF8ssctnmIc+hzeOw4ajj7ell7+EE mZXCfN/xCXfSwghKcJRl43LjRkdm+hK4RAo3HIYd/nddwRZOCj0yvvurlmOra98wdJyK aBd8dgx14g7dAzVvhYrW0qxF+ykDQi7SeXi/RHaobnO8I64CWx6tNIyY/fhdAi+GEE4h qNHw== X-Received: by 10.204.227.80 with SMTP id iz16mr7403943bkb.121.1365192203163; Fri, 05 Apr 2013 13:03:23 -0700 (PDT) MIME-Version: 1.0 X-Received: by 10.204.227.80 with SMTP id iz16mr7403938bkb.121.1365192202991; Fri, 05 Apr 2013 13:03:22 -0700 (PDT) Received: by 10.204.226.78 with HTTP; Fri, 5 Apr 2013 13:03:22 -0700 (PDT) In-Reply-To: References: Date: Fri, 5 Apr 2013 16:03:22 -0400 Message-ID: From: Yaron Minsky To: Anthony Tavener Cc: "caml-list@inria.fr" Content-Type: text/plain; charset=windows-1252 Content-Transfer-Encoding: quoted-printable X-Gm-Message-State: ALoCoQmagecpaHj4zguZ6kyIB7y+YZoDJzcTO4Oa5gXDmNPTeNHEjDjy1wIl0SzqLzslzBJwneUtZFrDEwu82Ks806vH6srpNRWVn6YP54XT2rWtI+AtUlx4vD46tVJa83gpFDAlY2c9a3y3tCqnPbZ6KScIRCU2lA== Subject: Re: [Caml-list] Heterogeneous dictionary On Fri, Apr 5, 2013 at 3:55 PM, Anthony Tavener 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 > wrote: >> >> On Fri, Apr 5, 2013 at 2:27 PM, Anthony Tavener >> 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 >> > wrote: >> >> >> >> On Thu, Apr 4, 2013 at 2:48 PM, Anthony Tavener >> >> 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 a= nd >> >> > a >> >> > few >> >> > others). Wouldn't it be a problem to have all types brought into th= is >> >> > 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 thi= s? >> >> > 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 enti= ty >> >> > (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 whi= ch >> >> > come >> >> > from other rules. So, dialog code might have a current_value, then.= .. >> >> > eg. >> >> > let modified_value =3D apply_modifiers_for_context entity `CharmR= oll >> >> > current_value >> >> > >> >> > There is a lot of work on my project which I've been avoiding becau= se >> >> > the >> >> > direct approach is building hairy nests of checks which call out to >> >> > code >> >> > everywhere... effectively splitting logic between the point of orig= in >> >> > 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 >> >> > 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 =3D struct >> >> >> let recovery =3D Univ_key.Key.create "recovery" Int.sexp_of_t >> >> >> let resist_pain =3D 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 =3D Univ_map.add_exn map key data in >> >> >> let map =3D >> >> >> 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 >> >> >> 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 t= he >> >> >> > solution!). >> >> >> > >> >> >> > >> >> >> > >> >> >> > On Thu, Apr 4, 2013 at 1:38 AM, Rapha=EBl Proust >> >> >> > >> >> >> > wrote: >> >> >> >> >> >> >> >> On Thu, Apr 4, 2013 at 1:45 AM, Anthony Tavener >> >> >> >> wrote: >> >> >> >> > [=85] >> >> >> >> >> >> >> >> And yet-another-solution, Ocsigen's Polytable: >> >> >> >> http://ocsigen.org/ocsigenserver/api/Polytables >> >> >> >> >> >> >> >> >> >> >> >> Cheers, >> >> >> >> -- >> >> >> >> ______________ >> >> >> >> Rapha=EBl 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 > >