[Haskell] Re: Global Variables and IO initializers
Benjamin Franksen
benjamin.franksen at bessy.de
Sat Nov 6 22:16:54 EST 2004
As an experiment, I just finished to change the Haskell Web Server with
Plugins such that all global variables (unsafePerformIO-style) are replaced
by standard argument passing. It wasn't difficult. The main work was
(1) get it to compile with ghc-6.2.2
(2) understand how the code is organized
(3) find out that implicit parameters have too many limitations to be usefull
as a general replacement
(4) find appropriate pattern(s) to get rid of the globals
Overall I think the code has somewhat improved. The parts that were written
with global variables are now shorter and more easily understood.
What I didn't expect was that modularity did *not* suffer, quite the opposite:
the interfaces became smaller. For instance the MimeTypes module exported two
routines:
initMimeTypes :: String -> IO () -- argument is file path to mime.conf
mimeTypeOf :: String -> MimeType -- convert file path to mime type
where unsafePerformIO was used not only to create the global variable for the
mime type map, but also for the conversion function (because it had to access
teh global var).
The new interface has only one routine:
initMimeTypes :: String -> IO (String -> MimeType)
-- argument is file path to mime.conf
-- result is file path to mimetype converter
and no unsafe feature is used: the result is a pure function.
Of course, the downside is that some of the functions (not many) now have one
or two additional arguments. OTOH one could argue that this is in fact an
advantage, as it makes all the dependencies crystal clear. It turned out, for
example, that of the two logging modules, ErrorLogger and AccessLogger, the
latter had a hidden dependency on the former. That dependency is now
expressed explicitly by giving the initialization routine for the
AccessLogger an extra argument (namely the error logging function).
Surely this is just one example, and not a very complex one. Nevertheless, I
am now less convinced that using global variables is in fact a good idea,
however convenient it may seem at first.
Ben
More information about the Haskell
mailing list