Haskell's missing mutable reference type

Oops, i did misread the example slightly sorry ^^ You’re using the IOScopedRef to implement modifySeverity not to modify the Logger value directly.

My point still stands though. Everything that (indirectly) uses this IOScopedRef needs to go through the logger variable anyway so you might as well use it to carry the state in a lexically scoped way.

OK, then tell me how I could obtain the same behaviour using a lexically-scoped variable but without IOScopedRef.

data Logger = Logger {
    logImpl :: Severity -> String -> IO (),
    baseSeverity :: Severity
}

logMsg :: Logger -> Severity -> String -> IO ()
logMsg logger severity msg = logger.logImpl (logger.baseSeverity + severity) msg

newLogger :: Severity -> Logger
newLogger baseSeverity = Logger { baseSeverity, logImpl = \severity message -> putStrLn ... }

modifySeverity :: Logger -> (Severity -> Severity) -> Logger
modifySeverity logger f = logger { baseSeverity = f logger.baseSeverity }

loggerExample :: IO ()
loggerExample = do
  let logger = newLogger 0
  logMsg logger 1 "Getting user"
  user <- getUser
  logMsg logger 1 ("Is VIP: " <> show (isVip user))
  let modification = if isVip user then (+ 10) else id
  d <- do
    logger <- pure (modifySeverity logger modification)
    logMsg logger 0 "Getting data"
    getData user
  writeData d
  logMsg logger 0 "Done"