I am writing a Tetris game while learning Haskell and I'm trying to make the following code more concise and easier to read. How can I improve it?Note that the function is not finished yet (There is no check for complete lines, for instance); I currently want to improve its readability.updateGame :: IORef InputsData -> IORef GameState -> IO()updateGame keysIORef gameIORef = do    game <- readIORef gameIORef    keys <- readIORef keysIORef    newTime <- getCurrentTime    elapsed <- getMilliseconds $ diffUTCTime newTime (time game)    -- Updating current time    modifyIORef gameIORef (\g -> g {time = newTime})    game <- readIORef gameIORef    -- Updating keys cooldown    modifyIORef gameIORef (\g -> g {keyCooldowns = updateCooldowns (keyCooldowns game) elapsed})    game <- readIORef gameIORef    -- Processing side movements    when (not $ isOnCooldown (keyCooldowns game) (SpecialKey KeyRight)) $ do        if right keys          then when (canTetrominoMove (currentTetromino game) (Helpers.R) (tank game)) $ do            modifyIORef gameIORef (\g -> g {currentTetromino = (currentTetromino g) {x = x (currentTetromino g) + 1}})            modifyIORef gameIORef (\g -> g {keyCooldowns = addCooldown (keyCooldowns game) (SpecialKey KeyRight) 100})          else if left keys            then when (canTetrominoMove (currentTetromino game) (Helpers.L) (tank game)) $ do              modifyIORef gameIORef (\g -> g {currentTetromino = (currentTetromino g) {x = x (currentTetromino g) - 1}})              modifyIORef gameIORef (\g -> g {keyCooldowns = addCooldown (keyCooldowns game) (SpecialKey KeyRight) 100})            else return ()    game <- readIORef gameIORef    -- Processing tetromino rotations    when (not $ isOnCooldown (keyCooldowns game) (Char 'z')) $ do        if xKey keys          then when (canTetrominoRotate (currentTetromino game) (Helpers.R) (tank game)) $ do            modifyIORef gameIORef (\g -> g {currentTetromino = rotateTetromino (currentTetromino g) Helpers.R})            modifyIORef gameIORef (\g -> g {keyCooldowns = addCooldown (keyCooldowns game) (Char 'z') 200})          else if zKey keys            then when (canTetrominoRotate (currentTetromino game) (Helpers.L) (tank game)) $ do              modifyIORef gameIORef (\g -> g {currentTetromino = rotateTetromino (currentTetromino g) Helpers.L})              modifyIORef gameIORef (\g -> g {keyCooldowns = addCooldown (keyCooldowns game) (Char 'z') 200})            else return ()    game <- readIORef gameIORef    -- Updating current tetromino falling time    modifyIORef gameIORef (\g -> g {tetrominoFallingTime = (tetrominoFallingTime g) - elapsed})    game <- readIORef gameIORef    -- Making current tetromino fall & restarting current tetromino falling time    when (tetrominoFallingTime game < 0) $ do        modifyIORef gameIORef (\g -> g {tetrominoFallingTime = (tetrominoFallingTime g) + getTetrominoFallingSpeed (difficultyLevel g)})        if canTetrominoFall (currentTetromino game) (tank game)            then do                modifyIORef gameIORef (\g -> g {currentTetromino = (currentTetromino g) {y = y (currentTetromino g) - 1}})            else do                modifyIORef gameIORef (\g -> g {tank = addTetrominoToTank (currentTetromino game) (tank game)})                let (currentTetromino', tetrominoBag', rndGen') = drawTetrominoFromBag (rndGen game) (tetrominoBag game)                modifyIORef gameIORef (\g -> g {currentTetromino = currentTetromino', rndGen = rndGen', tetrominoBag = tetrominoBag'})    addTimerCallback 1 $ updateGame keysIORef gameIORef    postRedisplay Nothing
UpdateGame function for Tetris
game;haskell;functional programming;event handling;tetris