[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