From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from nez-perce.inria.fr (nez-perce.inria.fr [192.93.2.78]) by yquem.inria.fr (Postfix) with ESMTP id 03A48BB81 for ; Thu, 9 Dec 2004 21:02:24 +0100 (CET) Received: from pauillac.inria.fr (pauillac.inria.fr [128.93.11.35]) by nez-perce.inria.fr (8.13.0/8.13.0) with ESMTP id iB9K2MHI017748 for ; Thu, 9 Dec 2004 21:02:22 +0100 Received: from nez-perce.inria.fr (nez-perce.inria.fr [192.93.2.78]) by pauillac.inria.fr (8.7.6/8.7.3) with ESMTP id VAA09774 for ; Thu, 9 Dec 2004 21:02:22 +0100 (MET) From: pad@ryxa.irisa.fr Received: from ryxa.irisa.fr (ryxa.irisa.fr [131.254.50.45]) by nez-perce.inria.fr (8.13.0/8.13.0) with ESMTP id iB9K2Ltq017744 for ; Thu, 9 Dec 2004 21:02:22 +0100 Received: (from pad@localhost) by ryxa.irisa.fr (8.11.6/8.11.6) id iB9K2IM24178; Thu, 9 Dec 2004 21:02:18 +0100 To: Michael Walter Cc: Jacques Garrigue , JEFHEN@safeco.com, caml-list@inria.fr Subject: Re: [Caml-list] environment idiom Reply-To: padiolea@irisa.fr References: <9410EC84C0872141B27A2726613EF45D02A52E08@psmrdcex01.psm.pin.safeco.com> <20041209.134735.79249569.garrigue@math.nagoya-u.ac.jp> <877e9a170412082202790e2cfb@mail.gmail.com> Date: 09 Dec 2004 21:02:18 +0100 In-Reply-To: <877e9a170412082202790e2cfb@mail.gmail.com> Message-ID: User-Agent: Gnus/5.09 (Gnus v5.9.0) Emacs/21.2 MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii X-Miltered: at nez-perce with ID 41B8AF4E.000 by Joe's j-chkmail (http://j-chkmail.ensmp.fr)! X-Miltered: at nez-perce with ID 41B8AF4D.000 by Joe's j-chkmail (http://j-chkmail.ensmp.fr)! X-Spam: no; 0.00; irisa:01 caml-list:01 o'caml:01 statically:01 haskell:01 o'caml:01 emulated:01 cheers:01 wrote:01 henrikson:01 threads:01 ocaml:01 variants:01 hashtbl:01 hashtbl:01 X-Spam-Checker-Version: SpamAssassin 3.0.0 (2004-09-13) on yquem.inria.fr X-Spam-Status: No, score=0.2 required=5.0 tests=NO_REAL_NAME autolearn=disabled version=3.0.0 X-Spam-Level: Michael Walter writes: > Is there such thing as implicit parameters in O'caml, basically > variables with dynamic extent. Could be (partially?) statically > checked, too, no? The haskell guys have invented implicit parameter cos they dont have side effect or global variables. In O'Caml we have those features so implicit parameter can easily be emulated. The rest is more a syntactic sugar question. > > Cheers, > Michael > > > On Thu, 09 Dec 2004 13:47:35 +0900 (JST), Jacques Garrigue > wrote: > > From: "HENRIKSON, JEFFREY" > > > > > > > > > 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 = > > 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 > > > > _______________________________________________ > 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