
Ralf Hinze
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
This paper claims ``unsafePerformIO is unsafe''. That's not actually true in the sense meant; unsafePerformIO merely has safety pre-conditions that the compiler can't check. However, there's nothing wrong with using it (or wrapping it) as long as the preconditions are checked. In fact, IMO, it's /better/ to use unsafePerformIO in a common case like this, because exactly when the preconditions are satisfied will be much better understood. The precondition (proof obligation) of unsafePerformIO is that the order in which unsafePerformIOs are performed cannot affect the outcome of the program. However, in this case, ordering doesn't matter: the only side effect is allocation of a new IORef, and IORefs are sufficiently opaque we don't care (or really know) about un-allocated IORefs while the only case we care about the now-allocated IORef is when we de-reference it. But, that forces the IORef, which executes the unsafePerformIO. So, whenever we access the variable, it is allocated. Therefore, the outcome of the program (regardless of the order of evaluation) is the same as if all such global variable declarations are executed before main begins executing. So, the outcome is independent of the order of evaluation. There you go: the precondition of unsafePerformIO is satisfied, so the usage is safe.
Cheers, Ralf
Jon Cast