Programming with Monads, e.g. the IO Monad, is pure functional programming. It is a common misconception that it isn't. You have full referential transparency and sound composition, since no effects are actually performed until the computation is run/interpreted.