Do you have a policy around the use of I/O monads versus specialized monads for controlling access like that?
We have a general Monad typeclass called "World" which gives access to MySQL, Redis, HTTP, Memcache, and so on. There are more specific Monad typeclasses if you have a function that, for example, should only ever talk to Memcache and nothing else. I think it's called SupportsMemcache.
My point about the Haskell type system is that the _ability_ to limit the operations in a context is a capability that few languages have.
We have a simple mechanism for controlling access to IO.
There are a series of type classes that provide access to all of the IO based services (mysql, redis, memcache, etc.). All of the request handlers are written to use these type classes not IO. There are two instances of the type classes, one pure for tests using fakes, and one real using IO.
We do not use Haskell exclusively -- we also have a pile of PHP and some Python -- but it's awesome to have such a great tool at our disposal. I've been very impressed at how mature GHC's runtime system is. The Haskell services have run perfectly for months with no problems.
The Haskell type system even lets us say, for example, that you cannot talk to MySQL within a Redis transaction, preventing entire classes of bugs.
(I have many complaints about Haskell too, but net net, it's an enormous win over PHP and Python.)