- IORef: Mutable references in the IO monad.
- STRef: Mutable references in the (strict) ST monad.
- MVar: synchronized mutable variables between threads.
STRef provides mutable references, IORef provides mutable references, exception catching, threads, and of course IO.
Rule of thumb: use the weakest abstraction.
An example situation in which you are forced to use IORefs (or their cousins MVars) is when having to share a mutable reference between two different execution threads.
- TVar is a mutable reference within STM, representing general shared state (~ IORef/STRef)
- TMVar is a reference to a slot that threads can use to communicate (~ MVar). Think of it as a single-element queue used for a communicating producer/consumer pair.
In short, TVar is general shared state, use it if you want atomic updates to data from arbitrary places. TMVar is a synchronization primitive, use it if you want a thread to wait until something becomes available, while another waits for something to be needed.