I'm sorry, I don't see the problem. You can encapsulate away the state behind an opaque type so that it can be only accessed by functions that you have defined. Whether this is a good choice is up to the programmer, but it's common practice in haskell to use domain-specific types wherever it makes sense.
For UIs and such, in addition to monads there are more powerful abstractions, but at no point is it necessary to leak information to the client. The common UI toolkits tend to have some impedance mismatch with FP because they've been designed with OOP in mind, but this is not the fault of FP.
Of course, in FP it often doesn't even make sense to encapsulate everything. Why hide useful data when it's guaranteed that any user will not be able to misuse it?
Haskell provides tools for abstraction that are IMO vastly superior to anything I've seen in an OOP language. If anything, you're more likely to have leaky abstractions and failed encapsulation in Java or C++ compared to Haskell, simply because of mutable state, closed classes, and limited expressiveness of the type system.