Okay, I was stupid, having ignored my own advice to always look at the
sources.
I stupidly assumed IO a was not a function-type. On retrospect, I can't
imagine, how that came to me.
I've looked it up now, and for ghc, I found
newtype IO a = IO (State# RealWorld -> (# State# RealWorld, a #))
which is more or less what I've arrived at, eventually.
For hugs, it's
newtype IO a = IO ((IOError -> IOResult) -> (a -> IOResult) -> IOResult),
which I find somewhat more contrived.
So I apologize for all the nonsense that came from that and happily agree that
getChar &c are well defined values of IO a.
Whether we have
putStrLn "hello" >> mzero === mzero
depends on what raiseIO# exactly does, I've no idea.
Again, sorry for all the fuss.
Thanks to (in alphabetical order) Jorge, Jules and Ketil for helping me out of
my error.
Daniel