Haskell bounded LRU cache over Data.Map

Haskell
import Data.IORef (IORef, atomicModifyIORef', newIORef)
import Data.List (minimumBy)
import Data.Ord (comparing)
import qualified Data.Map.Strict as M

type LRU k v = (Int, M.Map k (Int, v))

newLRU :: IO (IORef (LRU k v))
newLRU = newIORef (0, M.empty)

lruGet :: Ord k => k -> IORef (LRU k v) -> IO (Maybe v)
lruGet k ref = atomicModifyIORef' ref $ \(tick, m) -> case M.lookup k m of
  Nothing -> ((tick, m), Nothing)
  Just (_, v) -> ((tick + 1, M.insert k (tick + 1, v) m), Just v)

lruPut :: Ord k => Int -> k -> v -> IORef (LRU k v) -> IO ()
lruPut cap k v ref = atomicModifyIORef' ref $ \(tick, m) ->
  let m' = M.insert k (tick + 1, v) m
      keep | M.size m' <= cap = m'
           | otherwise = M.delete (fst (minimumBy (comparing snd) (M.toList m'))) m'
  in ((tick + 1, keep), ())