
Control.Concurrent.MVar uses `evaluate` in a couple places, and I don't understand why: modifyMVar :: MVar a -> (a -> IO (a,b)) -> IO b modifyMVar m io = mask $ \restore -> do a <- takeMVar m (a',b) <- restore (io a >>= evaluate) `onException` putMVar m a putMVar m a' return b modifyMVarMasked :: MVar a -> (a -> IO (a,b)) -> IO b modifyMVarMasked m io = mask_ $ do a <- takeMVar m (a',b) <- (io a >>= evaluate) `onException` putMVar m a putMVar m a' return b The general purpose is to make sure that the result of the IO action is forced to head normal form within the scope of the `catch` block created by `onException`. But in this context, I don't see why we need to use `evaluate` rather than just `seq`, or why that is desirable. Couldn't we just do this? modifyMVar m io = mask $ \restore -> do a <- takeMVar m (a',b) <- restore (io a >>= (pure $!)) `onException` putMVar m a putMVar m a' return b David