> Since exception can arise at any point, it is not possible to guarantee
atomicity of operation, hence mutable data structure may remain in
incorrect state in case of interruption.
Even if async exceptions didn't exist, we couldn't guarantee atomicity in general without specifically atomic functions (like atomicModifyIORef or STM), since another thread may access the data concurrently and create a data race.
If you're only talking about single-threaded cases—of which ST is _basically_ a subset[1]—I don't think you're really worried about _atomicity_, but about exception safety. Exception safety goes beyond async exceptions, since almost all IO actions can throw some form of synchronous exception. For those cases, you can use one of the many exception-cleanup functions, like finally, onException, bracket, or bracketOnError.
It's true that those functions don't work inside ST, but I'd argue you don't need them to. The expected behavior of code that receives an async exception is to (1) clean up after itself and (2) rethrow the exception. But as ST blocks are supposed to be free of externally-visible side effects, worrying about putting its variables back into some safe state is unnecessary[2].
To summarize:
* If you need true atomicity, you're in IO and dealing with multiple threads. I'd recommend sticking with STM unless you have a strong reason to do otherwise.
* If you are single threaded and in IO, you can get away with non-STM stuff more easily, and need to make sure you're using exception-aware functions.
* If you're inside ST, make sure any resources you acquire are cleaned up correctly, but otherwise you needn't worry about exceptions.
Also, you may be interested in reading the documentation for safe-exceptions[3], which talks more about async exception safety.
[1] I say basically since you'd have to pull out unsafe functions to fork a thread that has access to an STVar or similar, though it could be done.
[2] If you're doing something like binding to a C library inside ST, you may have some memory cleanup to perform, but the STVars and other data structures should never be visible again.