[Haskell-cafe] Re: [Haskell] Re: Global Variables and whatever

Claus Reinke claus.reinke at talk21.com
Tue Nov 9 05:05:15 EST 2004


> I take it the position of those who object to such things is not..
>  "Top level mutable variables are a very very bad thing and
>   should never ever be used (Errm..well unless they're really
>   necessary, in which case you should use C)."

more like: if you have two parts of your codebase, one of which
easily accomodates such variables and is already flooded with 
them, the other not, then it may be a good idea to put such 
variables in the first part.

but that doesn't mean that there aren't common programming
problems that are currently inconvenient in Haskell and could
be supported better, without the need for unsafePerformIO.

> As I have observed in an earlier post, the thread title
> chosen by the OP is a rather unfortunate choice of words IMO.
> I wish people stop talking about "global variables". Nobody is
> advocating the use of global mutable variables. 

perhaps you aren't, and some other posters in this thread aren't,
but it is one of the most common uses of unsafePerformIO, and
it is one of the subjects of this thread (and the ones before). then 
again, perhaps you're only thinking you're not talking about 
global mutable variables (the emphasis being more on mutable 
than on global).

if you look back at your own oneShot example, you might find
that the local MVar putting and taking isn't doing much at all, 
and the magic lies in the use of unsafePerformIO to share the
result of the IO action. so you could move the unsafePerformIO 
into your oneShot (if you're certain to inspect the result of
initialisation, you could avoid the strict application $!):

    Prelude System.IO.Unsafe> let realInit = putStrLn "okay"
    Prelude System.IO.Unsafe> let {oneShot :: IO a -> IO a; 
                                                      oneShot io = return $! unsafePerformIO io}
    Prelude System.IO.Unsafe> let userInit = oneShot realInit
    Prelude System.IO.Unsafe> userInit >>= print
    okay
    ()
    Prelude System.IO.Unsafe> userInit >>= print
    ()
    Prelude System.IO.Unsafe> userInit >>= print
    ()
    Prelude System.IO.Unsafe>

in other words, the core of your example is the variable userInit 
that is modified exactly once. but modified it is, even though userInit
is a Haskell variable, no MVar or other inherently modifiable thing.
depending on what realInit does (and being in IO a, that could be 
a lot), that may or may not be observable.

and as others pointed out, reasoning about programs involving 
unsafePerformIO involves contextual equivalences, no longer 
replacing equals in all contexts, so hoping for referential 
transparency in the general case might be a bit optimistic 
(that's why one has to disable compiler optimisations based 
on this property, after all). 

your specific case seems slightly less problematic since userInit 
is itself of type IO (), but in combination with the monad laws, 
one might still run into trouble -- every use of unsafePerformIO 
indicates a proof obligation that such trouble will not arise (or 
rather: under what constraints it won't).

> Actually, I know I'm not going to have to repeat this yet again
> because I'm going to make this is my last post on this thread.

as i said in my other post (waiting for moderator approval), there
are many people on this thread, and i'm not sure they are all talking
about the same thing. perhaps a good step forward would be for 
each concrete proposal to go into a separate thread (beginning 
with a summary of the use pattern to be covered and the concrete 
extension proposal claiming to do the job), and then to see whether 
there is any consensus for any of them.

cheers,
claus





More information about the Haskell-Cafe mailing list