You have to change the type signature if you want to do IO... Purity also means you can't read or write global variables, that's just another type of IO.
If you've written so much Haskell that you think of global variables (!) as a form of IO, then perhaps you would benefit from writing in C for a while? Beware internalizing abstractions so completely that you confuse them with the reality.
This came up a few times already and it really isn't as wrong as it sounds. In Haskell all "side effects", which include memory stores, are in the IO monad (with a few exceptions).
Writing a global variable is a side effect, because you change something other than the return value of a function. Reading would still break functional extensionality: Calling a function with equal arguments might yield different results in different contexts.
Being "in the IO monad" doesn't actually mean "doing IO". It's a bit of a badly punned name. It's more idiomatic to think of it as the RealWorld monad.
If you've written so much Haskell that you think of global variables (!) as a form of IO, then perhaps you would benefit from writing in C for a while? Beware internalizing abstractions so completely that you confuse them with the reality.