MVar
- can be empty
- used to implement synchronization patterns between threads
- allows one-way communication between threads
- can be faster than
TVarin some cases
TVar
- can not be empty
- atomic transactions
- “shared memory” between threads; can be used to implement, for example, a lookup cache from which multiple threads can read/write
- access is linear time in the number of operations in the transaction log
- long running transactions are vulnerable to starvation if there are many shorter transactions, preventing them from commiting successfully
IORef
- mutable pointer-like reference
- often used for destructive
IOwrites/updates - has atomic CAS operations, but complex transactional logic is better suited to a
TVar
There is not really a hard and fast rule for when to use MVar or TVar.
If the resource I’m guarding will ever be “missing” (as opposed to empty, consider Nothing vs Just mempty), then MVar often makes the most sense. If I will need to perform atomic blocks of modifications to the resource, then TVar is most suitable.