You either enforce 100% purity, or your language is not pure. Haskell chose to walk the former path. In that case reading global state needs to happen in the IO monad even if it is reading a couple of command line arguments. Though I completely agree it is nasty to change them in runtime, it is also assumed you know what you're doing when you tinker with them (cross-thread implications included.)
To a Haskell program, command line arguments are exactly the same outer world as your super important files.
To a Haskell program, command line arguments are exactly the same outer world as your super important files.