
Hello, Is it even possible to make a "global variable" in Haskell? If yes, how? Thanks. -- Zhbanov Pavel

Pavel G. Zhbanov wrote:
Is it even possible to make a "global variable" in Haskell? If yes, how?
The usual fudge is:
import IORef
import IOExts
globalVar :: IORef Int
globalVar = unsafePerformIO $ newIORef 0
However, beware of creating more than one "global variable" of the
same type. If you enable optimisation, common subexpression
elimination may result in both names referring to the same IORef.
--
Glynn Clements

Pavel G. Zhbanov wrote:
Is it even possible to make a "global variable" in Haskell? If yes, how?
The usual fudge is:
import IORef import IOExts
globalVar :: IORef Int globalVar = unsafePerformIO $ newIORef 0
However, beware of creating more than one "global variable" of the same type. If you enable optimisation, common subexpression elimination may result in both names referring to the same IORef.
John Hughes wrote a nice pearl on the subject, see http://www.math.chalmers.se/~rjmh/Globals.ps Cheers, Ralf

G'day all. On Fri, Jan 31, 2003 at 09:08:22AM +0100, Ralf Hinze wrote:
John Hughes wrote a nice pearl on the subject, see
Nice! Why isn't RefMonad in hslibs? Possibly because of the class signature: class Monad m => RefMonad m r | m -> r where {- etc -} It makes perfect sense for there to be more than one kind of "ref" for a given monad. Indeed, sometimes it's important. Quite often, I use a custom ref built on top of IORef which supports Ord, as this is needed for hash consing. Cheers, Andrew Bromage

Andrew J Bromage writes:
John Hughes wrote a nice pearl on the subject, see
Nice!
I do not think it is nice: I do not like any of the solutions Hughes considers in that paper because this problem can be handled much more simply with lexical scope and the IO monad. Just to get our bearings, let us first consider the solution that uses unsafePerformIO, which neither Hughes nor I prefer:
globalVar :: IORef Int globalVar = unsafePerformIO $ newIORef 0 foo = fff aaa bbb ccc bar = ggg xxx yyy zzz main = mmm >> nnn >> ooo
where the lines
foo = fff aaa bbb ccc bar = ggg xxx yyy zzz
stand in for a typically much larger chunk of code --the bulk of the program, let us call it. The solution I prefer replaces that last with
main=do globalVar<-newIORef 0 let foo = fff aaa bbb ccc bar = ggg xxx yyy zzz mmm >> nnn >> ooo
In other words, to be painfully explicit, the solution I prefer arranges the program so that (1) the global variable is the result of an IO computation just like every other IO computation; and (2) the global variable has a lexical scope that extends over the bulk of the program. It strikes me as a simple and obvious application of lexical scope, and I am surprised that it received no mention in the discussions on this list and in Hughes's paper. Of course, whenever you want to read or to write my global variable, you must be in the IO monad, but Hughes's solution requires being in a state monad. I do not consider the IO monad any worse than any other state monad. Am I the only one who prefers the above "lexical scope" solution to all the solutions in Hughes's paper and given previously on this list? Indentation One may raise the following objection to the "lexical scope" solution: levels of indentation are a scarce resource and a solution that consumes two of those levels before the program proper even starts is wasteful. I do not disagree with that objection; but I believe that the best response to the objection is not to abandon the the "lexical scope" solution but rather to adjust the syntactical definition of Haskell and of the do notation. E.g., we can eliminate one level of indentation by doing what GHCi does and eliminate the requirement for the "main=do" in programs. (This has the added benefit of shortening the Haskell version of "hello, world" to putStrLn "hello, world." Do not underestimate the attractiveness of a language with a short "hello, world" to the more practically-inclined programmers of the world.)
Why isn't RefMonad in hslibs?
It makes perfect sense for there to be more than one kind of "ref" for a given monad. Indeed, sometimes it's important. Quite often, I use a custom ref built on top of IORef which supports Ord, as this is needed for hash consing.
I think it is cleaner and simpler to ask the compiler maintainers to add an IORef instance to Ord. They know better how to implement it so it is fast. And it is the solution that puts the least cognitive demmand on readers of your program. (It's the easiest to learn, I mean.) I am not unalterably opposed to class RefMonad or to implicit variables. If someone makes a convincing argument that they are the best solution to an issue or problem, I will use them. But Hughes's paper does not convince me. Note that the global-variable solution I prefer will be more familiar to non-Haskell programmers. (To appreciate it, they have to "grok" monads, which can be a high hurdle, but they have to "grok" monads to appreciate Hughes's solution, too.) I wonder if Hughes's solution was motivated by a desire to avoid having to stay in the IO monad during all access to global variables. Several on this list have stated or implied that the IO monad is something to be resisted when possible. I do not agree with that position. But a general defense of the IO monad will take much more time than I have today.

Richard Uhtenwoldt writes: : | The solution I prefer replaces that last with | | >main=do | > globalVar<-newIORef 0 | > let | > foo = fff aaa bbb ccc | > bar = ggg xxx yyy zzz | > mmm >> nnn >> ooo : | Am I the only one who prefers the above "lexical scope" solution | to all the solutions in Hughes's paper and given previously on | this list? No, I prefer it too. It would be even nicer with parameterised modules, so that we could do something like main = do globalVar <- newIORef 0 let import (EvenBulkierThanFooAndBar globalVar) foo = fff aaa bbb ccc bar = ggg xxx yyy zzz mmm >> nnn >> ooo instead of passing globalVar to several of EvenBulkierThanFooAndBar's exported functions separately. - Tom

On Fri, 31 Jan 2003 07:47:43 +0000
Glynn Clements
The usual fudge is:
import IORef import IOExts
globalVar :: IORef Int globalVar = unsafePerformIO $ newIORef 0
I see in the documentation of unsafePerformIO that no one makes guarantees about the order in wich unsafePerformIO arguments are performed (especially they don't have to be executed BEFORE main), so this trick should not be adviced as a general practice; it should be pointed out that it works in GHC but could not work in other compilers. Vincenzo -- Fedeli alla linea, anche quando non c'è Quando l'imperatore è malato, quando muore,o è dubbioso, o è perplesso. Fedeli alla linea la linea non c'è. [CCCP]

Hello, Is it even possible to make a "global variable" in Haskell? If yes, how? Thanks.
(short answer, no time now...) Look here: http://www.haskell.org/pipermail/haskell-cafe/2002-January/002589.html Hope it helps ;) J.A.
participants (8)
-
Andrew J Bromage
-
Glynn Clements
-
Jorge Adriano
-
Nick Name
-
pavel@joker.botik.ru
-
Ralf Hinze
-
Richard Uhtenwoldt
-
Tom Pledger