Handling large ini files.

Derek Elkins ddarius@hotpop.com
Mon, 14 Jul 2003 18:08:43 -0400

On Sat, 12 Jul 2003 15:54:47 -0500
"Thaddeus L. Olczyk" <olczyk@interaccess.com> wrote:

> A while ago I looked at Haskell. I got stuck on a problem which
> basically caused me to stop using Haskell.
> Realising that I never asked anyone else how they would approach the
> deal, I decided to ask before I put the final chapter on Haskell.
> I have a program that requires a lot of customisation.
> As a result there is an initialization file with many entries
> ( typically 30-80 entries ). Some of these entries need to be
> accessed quite often, so that opening the file and reading in on
> demand is not really an option.

It would help if you were a bit more specific on what the program is
like or does ...

For a sequential program it seems relatively straightforward.  You load
the configuration at startup, you build an environment object that holds
all these settings (or better a record that contains function partially
applied to the relevant settings if only certain functions need to know
the options and the others are defined in terms of these).  You can then
pass around this (these) environment object(s) by hand, or use an
Environment (Reader) monad, or use GHC's implicit parameters extension. 
If you have a 'reload configuration file' command then you simply reread
the file, rebuild the environment object, and run the computation with
this new environment.  If options can be changed during the course of a
computation then you are likely in the IO monad and have a large range
of options available.  You can handle consistency checking and updating
more or less as you would in any language.

For a concurrent program things are somewhat more complicated, but not
much.  The simplest thing would be to poll a MVar that specifies when to
rebuild the environment object (obviously you wouldn't be constantly
polling it, just before you did whatever. You could use throwTo as
well). The type can be MVar(Maybe Environment) if nothing very complex
or thread specific needs to be done.  This would allow for threads to be
using the old configuration while some use the new, typically this isn't
a problem, using a webserver as an analogy, those threads would be
already started sessions.  If it's necessary to keep them consistent you
could likely use throwTo to terminate them gracefully, or just wait for
all of them to finish if they aren't potentially long-lived. 

> So the basic question is how do I handle access to these parameters?

Pass them around.  Use an environment or state monad to handle it if you
want cleaner looking code.  Finally, you could of course mostly stay in
an IO computation and solve the problem as you would in most any
imperative language.  Heck, there would still be benefits of using
Haskell as opposed to (most) imperative languages even if you took that
approach, such as, strong polymorphic static typing, higher-order
procedures, type classes, a flexible syntax, and quite a few others.