Dean Herington wrote (snipped)
Here's the scheme I would prefer for the "modify" subset of these functions. Existing functions are labeled "(e)", proposed functions "(p)". "(*)" indicates an existing function with a different interface.
(e) modifyMVar :: MVar a -> (a -> IO (a, b)) -> IO b (e) modifyMVar_ :: MVar a -> (a -> IO a) -> IO () (p) atomicModifyMVar :: MVar a -> (a -> (a, b)) -> IO b (p) atomicModifyMVar_ :: MVar a -> (a -> a) -> IO ()
(*) modifyIORef :: IORef a -> (a -> IO (a, b)) -> IO b (p) modifyIORef_ :: IORef a -> (a -> IO a) -> IO () (p) atomicModifyIORef :: IORef a -> (a -> (a, b)) -> IO b (p) atomicModifyIORef_ :: IORef a -> (a -> a) -> IO ()
Yes, why shouldn't we have atomicModifyMVar? Of course it will block if the MVar is empty, but that doesn't seem particularly important. I know Alastair thinks this is only a question of efficiency. To me though efficiency is important. Also I like the idea of replacing two primitives (readIORef and writeIORef) by one; you can define all accesses to IORefs in terms of atomicModifyIORef.