From: Michael Walter <michael.walter@gmail.com>
To: Jacques Garrigue <garrigue@math.nagoya-u.ac.jp>
Cc: JEFHEN@safeco.com, caml-list@inria.fr
Subject: Re: [Caml-list] environment idiom
Date: Thu, 9 Dec 2004 01:02:16 -0500 [thread overview]
Message-ID: <877e9a170412082202790e2cfb@mail.gmail.com> (raw)
In-Reply-To: <20041209.134735.79249569.garrigue@math.nagoya-u.ac.jp>
Is there such thing as implicit parameters in O'caml, basically
variables with dynamic extent. Could be (partially?) statically
checked, too, no?
Cheers,
Michael
On Thu, 09 Dec 2004 13:47:35 +0900 (JST), Jacques Garrigue
<garrigue@math.nagoya-u.ac.jp> wrote:
> From: "HENRIKSON, JEFFREY" <JEFHEN@safeco.com>
>
>
>
> > I am interested in the idiom of passing a number of parameters by some
> > kind of "environment" variable. Think of a web server with hundredes of
> > functions for processing markup and other things, only 3 of which need
> > to detect the browser. It's bad maintainability to explicitly pass
> > browserid through hundreds of functions which don't use it. And of
> > course, we must separate the state of the calling threads so as to not
> > cheat with global variables or some such thing.
> >
> > There seem to be two main candidates for such an idiom in Ocaml, objects
> > and polymorphic variants.
>
> [...]
>
> > And the polymorphic variant way, roughly:
> > let h = Hashtbl.create 10;;
> >
> > Hashtbl.add h `Banana (`Banana "b");;
> > Hashtbl.add h `Apple (`Apple "a");;
> > Hashtbl.add h `Pear (`Pear "p");;
>
> This seems a bit of an overkill: I would rather write directly
> let env = [`Banana "b"; `Apple "a"; `Pear "p"]
> Which would give you more or less the same typing.
>
> > Each of these idioms has its own advantage:
> >
> > In the object way the compiler verifies that the functions are passed
> > objects which contain all their needed configuration keys. But if I
> > understand correctly, we must at some point construct an environment
> > object which has _all_ the keys, even if we don't know them yet. We can
> > add by mutation, but we cannot simply leave them out and add them as we
> > get to functions which need them.
>
> A common way to do it would be to have a class defining defaults,
> and inherit and override it in your environment object.
> I'm not sure of how you intend to use your environment.
> But you're right that it is difficult to make changes incremental,
> since ocaml have no incrementally extendable records.
>
> Note also that while you cannot extend an object, you can extend a
> class, and you can use local modules to define classes locally.
> Yet, you cannot pass classes (or modules) to functions, so this does not
> solve your problem.
>
> > In the pv way the construction can be made incremental. Ie, if we
> > changed the hashtable to a list or immutable queue, we could add keys as
> > we go. But at least as I have it set up, the variants are not placing
> > restrictions on the existence of keys in the environment, other than
> > saying "we can understand at least this many keys," which is of course
> > meaningless. Is there a way to turn the typing around to say "we
> > require at least these keys"?
>
> No: any variant type is a subtype of a variant type containing more
> keys, so you would be able to cheat anyway.
>
> > In general, what are the typing and run-time limitations around each
> > way?
>
> I think you've described them correctly: objects offer exact typing,
> but cannot be extended incrementally, and lists of porlymorphic
> variants enforce typing but do not guarantee what keys are defined.
>
> In terms of efficiency, objects generate more code, but performance should
> be comparable.
>
> Note that ocaml contains a third way to do that, which in some cases is
> more natural. You can use labelled arguments. This means that you must
> pass all the arguments explicitly, but you are no longer restricted by
> their order. Some arguments may be optional.
> Depending on your goal, this may be the safest way to pass parameters.
>
> let bar ~pear s = pear^s
> let foo ~apple ~banana ~pear s = bar ~pear (apple^banana^s)
>
> You may look at code in lablgtk2 for clever ways to handle long lists
> of parameters this way. (But this doesn't fit your web server
> example.)
>
> A last way, which could work very well with your web server example,
> is to use records in place of objects, and update them using
> with. Then you can use clever typing.
>
> module Option : sig
> type (+'a,+'b) t
> type abs = [`abs|`pre]
> type pre = [`pre]
> val none : ('a, abs) t
> val some : 'a -> ('a, 'b) t
> val get : ('a, pre) t -> 'a
> end = struct
> type ('a,'b) t = 'a option
> type abs = [`abs|`pre]
> type pre = [`pre]
> let none = None
> let some x = Some x
> let get = function Some x -> x | None -> assert false
> end
>
> open Option
>
> type ('a,'b,'c) env =
> {apple: (string, 'b) t; banana: (string, 'a) t; pear: (string, 'c) t}
>
> # let empty = {apple=none; banana=none; pear=none}
> val empty : (abs, abs, abs) env
>
> # let e1 = {empty with pear=some "Williams"}
> val e1 : (abs, abs, 'a) env
> # let e2 = {e1 with apple=some "Golden"; banana=some "Plantin"}
> val e2 : ('a, 'b, 'c) env
>
> # let bar env s =
> get env.pear ^ s
> val bar : ('a, 'b, pre) env -> string -> string
> # let foo env s =
> bar env (get env.apple ^ get env.banana ^ s)
> val foo : (pre, pre, pre) env -> string -> string
>
> # foo e2 "!";;
> - : string = "WilliamsGoldenPlantin!"
>
> # foo e1;;
> This expression has type (Option.abs, Option.abs, 'a) env
> but is here used with type (Option.pre, Option.pre, Option.pre) env
> Type Option.abs = [ `abs | `pre ] is not compatible with type
> Option.pre = [ `pre ]
>
> Polymorphic variants are not essential here.
> They just allow one to forget about some fields of the environment
> without physically modifying it. For instance:
>
> # let forget_pear env = (env :> (_,_,abs) env);;
> val forget_pear : ('a, 'b, [< abs ]) env -> ('a, 'b, abs) env
>
> If you don't need this kind of operation, you could choose a simpler
> interface, which would be enough in most cases.
> module Option : sig
> type (+'a,+'b) t
> type abs
> type pre
> val none : ('a, abs) t
> val some : 'a -> ('a, 'b) t
> val get : ('a, pre) t -> 'a
> end
>
> By the way, I had thought of a clever way to obtain nicer types:
> type 'u env =
> {banana: (string, 'a) t; apple: (string, 'b) t; pear: (string, 'c) t}
> constraint 'u = <banana:'a; apple:'b; pear:'c>
> But after fiddling with it I discovered a serious bug in the type
> checker. Please do not use constraints on type variables that do not
> appear in the type itself until this is solved. Sorry for the
> inconvenience.
>
> Jacques Garrigue
>
>
>
> _______________________________________________
> Caml-list mailing list. Subscription management:
> http://yquem.inria.fr/cgi-bin/mailman/listinfo/caml-list
> Archives: http://caml.inria.fr
> Beginner's list: http://groups.yahoo.com/group/ocaml_beginners
> Bug reports: http://caml.inria.fr/bin/caml-bugs
>
next prev parent reply other threads:[~2004-12-09 6:02 UTC|newest]
Thread overview: 57+ messages / expand[flat|nested] mbox.gz Atom feed top
2004-12-09 2:07 HENRIKSON, JEFFREY
2004-12-09 4:47 ` [Caml-list] " Jacques Garrigue
2004-12-09 6:02 ` Michael Walter [this message]
2004-12-09 11:28 ` Jacques Garrigue
2004-12-09 20:02 ` pad
2004-12-09 23:11 ` Jacques Garrigue
2004-12-10 2:30 ` skaller
2004-12-09 9:09 ` Richard Jones
2004-12-09 13:12 ` [Caml-list] " Ville-Pertti Keinonen
2004-12-10 11:59 ` Richard Jones
2004-12-10 10:52 ` [Caml-list] " Andrej Bauer
2004-12-10 12:13 ` Richard Jones
2004-12-10 23:35 ` Jacques Garrigue
2004-12-11 2:30 ` skaller
2004-12-11 14:31 ` Andrej Bauer
2004-12-11 18:13 ` Markus Mottl
2004-12-11 23:56 ` skaller
2004-12-12 2:36 ` William Lovas
2004-12-12 5:33 ` skaller
2004-12-12 19:09 ` Michael Walter
2004-12-13 0:48 ` skaller
2004-12-13 2:03 ` Michael Walter
2004-12-13 2:05 ` Michael Walter
[not found] ` <877e9a170412121844b633bb8@mail.gmail.com>
2004-12-13 2:45 ` Michael Walter
2004-12-13 6:18 ` skaller
2004-12-13 7:08 ` skaller
2004-12-13 9:56 ` Michael Walter
2004-12-13 12:59 ` skaller
2004-12-13 8:56 ` Thomas Fischbacher
2004-12-13 9:21 ` Jacques Garrigue
2004-12-13 10:05 ` Michael Walter
2004-12-13 10:29 ` Thomas Fischbacher
2004-12-13 21:16 ` Michael Walter
2004-12-13 10:20 ` Thomas Fischbacher
2004-12-13 12:09 ` Jacques Garrigue
2004-12-13 12:48 ` Thomas Fischbacher
2004-12-13 14:09 ` skaller
2004-12-13 21:39 ` Michael Walter
2004-12-13 13:22 ` skaller
2004-12-13 16:54 ` Marcin 'Qrczak' Kowalczyk
2004-12-13 18:44 ` Thomas Fischbacher
2004-12-13 10:11 ` Michael Walter
2004-12-13 11:46 ` skaller
2004-12-13 5:41 ` skaller
2004-12-13 9:29 ` Michael Walter
2004-12-13 12:30 ` skaller
2004-12-13 13:49 ` Martin Berger
2004-12-12 23:03 ` Thomas Fischbacher
2004-12-13 1:26 ` skaller
2004-12-13 8:37 ` Thomas Fischbacher
2004-12-13 10:53 ` skaller
2004-12-13 11:38 ` Martin Berger
2004-12-13 13:33 ` skaller
2004-12-13 12:01 ` Thomas Fischbacher
2004-12-13 13:41 ` skaller
2004-12-11 23:29 ` skaller
2004-12-12 0:21 ` Jacques Carette
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=877e9a170412082202790e2cfb@mail.gmail.com \
--to=michael.walter@gmail.com \
--cc=JEFHEN@safeco.com \
--cc=caml-list@inria.fr \
--cc=garrigue@math.nagoya-u.ac.jp \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox