> it's essentially impossible to tell in many cases, so I think there's an argument for being 'honest' about this and not making type guarantees for things that aren't necessarily true
I see what you mean, e.g. an innocent-looking message to stdout might be piped into a file, on a FUSE filesystem which could do anything. But I don't think that's really Haskell's problem; it's a case of Haskell conforming to an external interface, and anything plugged into that interface is the concern of the user/sysadmin.
The main reason that Haskell's IO is monolithic is that there's traditionally not been a nice way to combine monads (monad transformers get the job done, but there's always been a desire for something better).
Effect systems are becoming popular because they are more composable, and hence newer languages (PureScript, Idris, etc.) are favouring those over monads.