How does Haskell deal with things like memory-mapped I/O or signal handlers where the value of a variable can be changed by factors outside of the programmer's control?
Side effecting computations that depend on the "real world" go into an IO monad. The game in Haskell is shifting as much of the codebase as possible into pure functions/non-side-effecting code, because it's easier to reason about and prove correct.
IORefs usually, which can only be manipulated within the IO monad, so they tend to only get used at the top level and passed down to pure functions as parameters.