I'm a little disappointed that the article suggests that the IO monad makes Haskell impure. While it is certainly true that unsafePerformIO violates purity(and type safety, as well), without it, IO is perfectly pure. It's just that if an IO a value happens to end up in main or something referenced from main, input and output happen. From the language's perspective, the IO monad functions could all be perfectly pure and have no relation to input or output(putStrLn could be a no-op, input functions could always return the same thing). It would be utterly useless for its intended purpose, but there would be no difference in terms of its purity.