This comment is somewhat silly. The whole notion of segregating effects is about what a programmer cannot do, and not about what they can.
In ML, maybe you can segregate effects, but it is of limited value, as all of the code you use might be hiding procedural effects behind the seemingly innocent types.
In Haskell, when I read an API, I know no effects lurk behind the pure type signatures.
To be fair, Harper's comment is practically a pretty silly proposition. But the primary technical claim of his post (SML supports monads) is true. This is a common issue with Harper: he rarely says anything factually incorrect, but the moral conclusions he draws are out of proportion with the technical points he makes.
While there may very well be monads in SML, he still haven't made it clear the Monad abstraction is possible, because he hasn't actually written any code that's generalized to any monad (e.g: Haskell's sequence, liftM2, and so forth).
In Haskell, all the effects are encoded into the type. You might have 200 different monad transformers -- maybe monad, list monad, state monad, etc etc all layered on top of each other -- but the information is there if you want to decode what the type means. Effects can sneak in with unsafePerformIO, but this is also considered terrible style. The huge types you can get from all the monads and monad transformers can certainly be a problem, but there's a tradeoff to be considered here that Harper just dismisses.
I wonder how often unsafePerformIO : IO 'a -> 'a is employed
To answer you directly, I've read code in various Haskell packages, everything from mime to snap, and AFAICT, it is typically used when you need to call a C library. Suppose you need to use OpenSSL's digest algorithms, for example. Because we technically don't know whether or not that library will have effects, we have to use unsafePerformIO.