The signature of modifyIORef
is straightforward enough:
modifyIORef :: IORef a -> (a -> a) -> IO ()
Unfortunately, this is not thread safe. There is an alternative that adresses this issue:
atomicModifyIORef :: IORef a -> (a -> (a,b)) -> IO b
What exactly are the differences between these two functions? How am I supposed to use the b
parameter when modifying an IORef
that might be read from another thread?
As you stated in a comment, without concurrency you'd be able to just write something like
modifyAndReturn ref f = do
old <- readIORef ref
let !(new, r) = f old
writeIORef r new
return r
But in a concurrent context, someone else could change the reference between the read and the write.