    {-# LANGUAGE DerivingVia #-}
    {-# LANGUAGE PatternSynonyms #-}
    --
    -- (c) The University of Glasgow 2002-2006
    --

    -- | The IO Monad with an environment
    --
    -- The environment is passed around as a Reader monad but
    -- as its in the IO monad, mutable references can be used
    -- for updating state.
    --
    module GHC.Data.IOEnv (
            IOEnv, -- Instance of Monad

            -- Monad utilities
            module GHC.Utils.Monad,

            -- Errors
            failM, failWithM,
            IOEnvFailure(..),

            -- Getting at the environment
            getEnv, setEnv, updEnv,

            runIOEnv, unsafeInterleaveM, uninterruptibleMaskM_,
            tryM, tryAllM, tryMostM, fixM,

            -- I/O operations
            IORef, newMutVar, readMutVar, writeMutVar, updMutVar,
            atomicUpdMutVar, atomicUpdMutVar'
      ) where

    import GHC.Prelude

    import GHC.Driver.DynFlags
    import {-# SOURCE #-} GHC.Driver.Hooks
    import GHC.IO (catchException)
    import GHC.Utils.Exception
    import GHC.Unit.Module
    import GHC.Utils.Panic

    import Data.IORef       ( IORef, newIORef, readIORef, writeIORef, modifyIORef,
                              atomicModifyIORef, atomicModifyIORef' )
    import System.IO.Unsafe ( unsafeInterleaveIO )
    import System.IO        ( fixIO )
    import Control.Monad
    import Control.Monad.Trans.Reader
    import Control.Monad.Catch (MonadCatch, MonadMask, MonadThrow)
    import GHC.Utils.Monad
    import GHC.Utils.Logger
    import Control.Applicative (Alternative(..))
    import GHC.Exts( oneShot )
    import Control.Concurrent.MVar (newEmptyMVar, readMVar, putMVar)
    import Control.Concurrent (forkIO, killThread)

    ----------------------------------------------------------------------
    -- Defining the monad type
    ----------------------------------------------------------------------

    newtype IOEnv env a = IOEnv' (env -> IO a)
      deriving (Monad (IOEnv env)
    Monad (IOEnv env) =>
    (forall e a. (HasCallStack, Exception e) => e -> IOEnv env a)
    -> MonadThrow (IOEnv env)
    forall env. Monad (IOEnv env)
    forall e a. (HasCallStack, Exception e) => e -> IOEnv env a
    forall env e a. (HasCallStack, Exception e) => e -> IOEnv env a
    forall (m :: * -> *).
    Monad m =>
    (forall e a. (HasCallStack, Exception e) => e -> m a)
    -> MonadThrow m
    $cthrowM :: forall env e a. (HasCallStack, Exception e) => e -> IOEnv env a
    throwM :: forall e a. (HasCallStack, Exception e) => e -> IOEnv env a
    MonadThrow, MonadThrow (IOEnv env)
    MonadThrow (IOEnv env) =>
    (forall e a.
     (HasCallStack, Exception e) =>
     IOEnv env a -> (e -> IOEnv env a) -> IOEnv env a)
    -> MonadCatch (IOEnv env)
    forall env. MonadThrow (IOEnv env)
    forall e a.
    (HasCallStack, Exception e) =>
    IOEnv env a -> (e -> IOEnv env a) -> IOEnv env a
    forall env e a.
    (HasCallStack, Exception e) =>
    IOEnv env a -> (e -> IOEnv env a) -> IOEnv env a
    forall (m :: * -> *).
    MonadThrow m =>
    (forall e a.
     (HasCallStack, Exception e) =>
     m a -> (e -> m a) -> m a)
    -> MonadCatch m
    $ccatch :: forall env e a.
    (HasCallStack, Exception e) =>
    IOEnv env a -> (e -> IOEnv env a) -> IOEnv env a
    catch :: forall e a.
    (HasCallStack, Exception e) =>
    IOEnv env a -> (e -> IOEnv env a) -> IOEnv env a
    MonadCatch, MonadCatch (IOEnv env)
    MonadCatch (IOEnv env) =>
    (forall b.
     HasCallStack =>
     ((forall a. IOEnv env a -> IOEnv env a) -> IOEnv env b)
     -> IOEnv env b)
    -> (forall b.
        HasCallStack =>
        ((forall a. IOEnv env a -> IOEnv env a) -> IOEnv env b)
        -> IOEnv env b)
    -> (forall a b c.
        HasCallStack =>
        IOEnv env a
        -> (a -> ExitCase b -> IOEnv env c)
        -> (a -> IOEnv env b)
        -> IOEnv env (b, c))
    -> MonadMask (IOEnv env)
    forall env. MonadCatch (IOEnv env)
    forall b.
    HasCallStack =>
    ((forall a. IOEnv env a -> IOEnv env a) -> IOEnv env b)
    -> IOEnv env b
    forall env b.
    HasCallStack =>
    ((forall a. IOEnv env a -> IOEnv env a) -> IOEnv env b)
    -> IOEnv env b
    forall a b c.
    HasCallStack =>
    IOEnv env a
    -> (a -> ExitCase b -> IOEnv env c)
    -> (a -> IOEnv env b)
    -> IOEnv env (b, c)
    forall env a b c.
    HasCallStack =>
    IOEnv env a
    -> (a -> ExitCase b -> IOEnv env c)
    -> (a -> IOEnv env b)
    -> IOEnv env (b, c)
    forall (m :: * -> *).
    MonadCatch m =>
    (forall b. HasCallStack => ((forall a. m a -> m a) -> m b) -> m b)
    -> (forall b.
        HasCallStack =>
        ((forall a. m a -> m a) -> m b) -> m b)
    -> (forall a b c.
        HasCallStack =>
        m a -> (a -> ExitCase b -> m c) -> (a -> m b) -> m (b, c))
    -> MonadMask m
    $cmask :: forall env b.
    HasCallStack =>
    ((forall a. IOEnv env a -> IOEnv env a) -> IOEnv env b)
    -> IOEnv env b
    mask :: forall b.
    HasCallStack =>
    ((forall a. IOEnv env a -> IOEnv env a) -> IOEnv env b)
    -> IOEnv env b
    $cuninterruptibleMask :: forall env b.
    HasCallStack =>
    ((forall a. IOEnv env a -> IOEnv env a) -> IOEnv env b)
    -> IOEnv env b
    uninterruptibleMask :: forall b.
    HasCallStack =>
    ((forall a. IOEnv env a -> IOEnv env a) -> IOEnv env b)
    -> IOEnv env b
    $cgeneralBracket :: forall env a b c.
    HasCallStack =>
    IOEnv env a
    -> (a -> ExitCase b -> IOEnv env c)
    -> (a -> IOEnv env b)
    -> IOEnv env (b, c)
    generalBracket :: forall a b c.
    HasCallStack =>
    IOEnv env a
    -> (a -> ExitCase b -> IOEnv env c)
    -> (a -> IOEnv env b)
    -> IOEnv env (b, c)
    MonadMask, Monad (IOEnv env)
    Monad (IOEnv env) =>
    (forall a. (a -> IOEnv env a) -> IOEnv env a)
    -> MonadFix (IOEnv env)
    forall env. Monad (IOEnv env)
    forall a. (a -> IOEnv env a) -> IOEnv env a
    forall env a. (a -> IOEnv env a) -> IOEnv env a
    forall (m :: * -> *).
    Monad m =>
    (forall a. (a -> m a) -> m a) -> MonadFix m
    $cmfix :: forall env a. (a -> IOEnv env a) -> IOEnv env a
    mfix :: forall a. (a -> IOEnv env a) -> IOEnv env a
    MonadFix) via (ReaderT env IO)

    -- See Note [The one-shot state monad trick] in GHC.Utils.Monad
    instance Functor (IOEnv env) where
       fmap :: forall a b. (a -> b) -> IOEnv env a -> IOEnv env b
    fmap a -> b
    f (IOEnv env -> IO a
    g) = (env -> IO b) -> IOEnv env b
    forall env a. (env -> IO a) -> IOEnv env a
    IOEnv ((env -> IO b) -> IOEnv env b) -> (env -> IO b) -> IOEnv env b
    forall a b. (a -> b) -> a -> b
    $ \env
    env -> (a -> b) -> IO a -> IO b
    forall a b. (a -> b) -> IO a -> IO b
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap a -> b
    f (env -> IO a
    g env
    env)
       a
    a <$ :: forall a b. a -> IOEnv env b -> IOEnv env a
    <$ IOEnv env -> IO b
    g     = (env -> IO a) -> IOEnv env a
    forall env a. (env -> IO a) -> IOEnv env a
    IOEnv ((env -> IO a) -> IOEnv env a) -> (env -> IO a) -> IOEnv env a
    forall a b. (a -> b) -> a -> b
    $ \env
    env -> env -> IO b
    g env
    env IO b -> IO a -> IO a
    forall a b. IO a -> IO b -> IO b
    forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
    >> a -> IO a
    forall a. a -> IO a
    forall (f :: * -> *) a. Applicative f => a -> f a
    pure a
    a

    instance MonadIO (IOEnv env) where
       liftIO :: forall a. IO a -> IOEnv env a
    liftIO IO a
    f = (env -> IO a) -> IOEnv env a
    forall env a. (env -> IO a) -> IOEnv env a
    IOEnv (\env
    _ -> IO a
    f)

    pattern IOEnv :: forall env a. (env -> IO a) -> IOEnv env a
    pattern $mIOEnv :: forall {r} {env} {a}.
    IOEnv env a -> ((env -> IO a) -> r) -> ((# #) -> r) -> r
    $bIOEnv :: forall env a. (env -> IO a) -> IOEnv env a
    IOEnv m <- IOEnv' m
      where
        IOEnv env -> IO a
    m = (env -> IO a) -> IOEnv env a
    forall env a. (env -> IO a) -> IOEnv env a
    IOEnv' ((env -> IO a) -> env -> IO a
    forall a b. (a -> b) -> a -> b
    oneShot env -> IO a
    m)

    {-# COMPLETE IOEnv #-}

    unIOEnv :: IOEnv env a -> (env -> IO a)
    unIOEnv :: forall env a. IOEnv env a -> env -> IO a
    unIOEnv (IOEnv env -> IO a
    m) = env -> IO a
    m

    instance Monad (IOEnv m) where
        >>= :: forall a b. IOEnv m a -> (a -> IOEnv m b) -> IOEnv m b
    (>>=)  = IOEnv m a -> (a -> IOEnv m b) -> IOEnv m b
    forall m a b. IOEnv m a -> (a -> IOEnv m b) -> IOEnv m b
    thenM
        >> :: forall a b. IOEnv m a -> IOEnv m b -> IOEnv m b
    (>>)   = IOEnv m a -> IOEnv m b -> IOEnv m b
    forall a b. IOEnv m a -> IOEnv m b -> IOEnv m b
    forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
    (*>)

    instance MonadFail (IOEnv m) where
        fail :: forall a. String -> IOEnv m a
    fail String
    _ = IOEnv m a
    forall env a. IOEnv env a
    failM -- Ignore the string

    instance Applicative (IOEnv m) where
        pure :: forall a. a -> IOEnv m a
    pure = a -> IOEnv m a
    forall a env. a -> IOEnv env a
    returnM
        IOEnv m -> IO (a -> b)
    f <*> :: forall a b. IOEnv m (a -> b) -> IOEnv m a -> IOEnv m b
    <*> IOEnv m -> IO a
    x = (m -> IO b) -> IOEnv m b
    forall env a. (env -> IO a) -> IOEnv env a
    IOEnv (\ m
    env -> m -> IO (a -> b)
    f m
    env IO (a -> b) -> IO a -> IO b
    forall a b. IO (a -> b) -> IO a -> IO b
    forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
    <*> m -> IO a
    x m
    env )
        *> :: forall a b. IOEnv m a -> IOEnv m b -> IOEnv m b
    (*>) = IOEnv m a -> IOEnv m b -> IOEnv m b
    forall m a b. IOEnv m a -> IOEnv m b -> IOEnv m b
    thenM_

    returnM :: a -> IOEnv env a
    returnM :: forall a env. a -> IOEnv env a
    returnM a
    a = (env -> IO a) -> IOEnv env a
    forall env a. (env -> IO a) -> IOEnv env a
    IOEnv (\ env
    _ -> a -> IO a
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return a
    a)

    thenM :: IOEnv env a -> (a -> IOEnv env b) -> IOEnv env b
    thenM :: forall m a b. IOEnv m a -> (a -> IOEnv m b) -> IOEnv m b
    thenM (IOEnv env -> IO a
    m) a -> IOEnv env b
    f = (env -> IO b) -> IOEnv env b
    forall env a. (env -> IO a) -> IOEnv env a
    IOEnv (\ env
    env -> do { r <- env -> IO a
    m env
    env ;
                                             unIOEnv (f r) env })

    thenM_ :: IOEnv env a -> IOEnv env b -> IOEnv env b
    thenM_ :: forall m a b. IOEnv m a -> IOEnv m b -> IOEnv m b
    thenM_ (IOEnv env -> IO a
    m) IOEnv env b
    f = (env -> IO b) -> IOEnv env b
    forall env a. (env -> IO a) -> IOEnv env a
    IOEnv (\ env
    env -> do { _ <- env -> IO a
    m env
    env ; unIOEnv f env })

    failM :: IOEnv env a
    failM :: forall env a. IOEnv env a
    failM = (env -> IO a) -> IOEnv env a
    forall env a. (env -> IO a) -> IOEnv env a
    IOEnv (\ env
    _ -> IOEnvFailure -> IO a
    forall e a. (HasCallStack, Exception e) => e -> IO a
    throwIO IOEnvFailure
    IOEnvFailure)

    failWithM :: String -> IOEnv env a
    failWithM :: forall m a. String -> IOEnv m a
    failWithM String
    s = (env -> IO a) -> IOEnv env a
    forall env a. (env -> IO a) -> IOEnv env a
    IOEnv (\ env
    _ -> IOError -> IO a
    forall a. IOError -> IO a
    ioError (String -> IOError
    userError String
    s))

    data IOEnvFailure = IOEnvFailure

    instance Show IOEnvFailure where
        show :: IOEnvFailure -> String
    show IOEnvFailure
    IOEnvFailure = String
    "IOEnv failure"

    instance Exception IOEnvFailure

    instance ContainsDynFlags env => HasDynFlags (IOEnv env) where
        getDynFlags :: IOEnv env DynFlags
    getDynFlags = do env <- IOEnv env env
    forall env. IOEnv env env
    getEnv
                         return $! extractDynFlags env

    instance ContainsHooks env => HasHooks (IOEnv env) where
        getHooks :: IOEnv env Hooks
    getHooks = do env <- IOEnv env env
    forall env. IOEnv env env
    getEnv
                      return $! extractHooks env

    instance ContainsLogger env => HasLogger (IOEnv env) where
        getLogger :: IOEnv env Logger
    getLogger = do env <- IOEnv env env
    forall env. IOEnv env env
    getEnv
                       return $! extractLogger env

    instance ContainsModule env => HasModule (IOEnv env) where
        getModule :: IOEnv env Module
    getModule = do env <- IOEnv env env
    forall env. IOEnv env env
    getEnv
                       return $ extractModule env

    ----------------------------------------------------------------------
    -- Fundamental combinators specific to the monad
    ----------------------------------------------------------------------

    ---------------------------
    runIOEnv :: env -> IOEnv env a -> IO a
    runIOEnv :: forall env a. env -> IOEnv env a -> IO a
    runIOEnv env
    env (IOEnv env -> IO a
    m) = env -> IO a
    m env
    env

    ---------------------------
    {-# NOINLINE fixM #-}
      -- Aargh!  Not inlining fixM alleviates a space leak problem.
      -- Normally fixM is used with a lazy tuple match: if the optimiser is
      -- shown the definition of fixM, it occasionally transforms the code
      -- in such a way that the code generator doesn't spot the selector
      -- thunks.  Sigh.

    fixM :: (a -> IOEnv env a) -> IOEnv env a
    fixM :: forall a env. (a -> IOEnv env a) -> IOEnv env a
    fixM a -> IOEnv env a
    f = (env -> IO a) -> IOEnv env a
    forall env a. (env -> IO a) -> IOEnv env a
    IOEnv (\ env
    env -> (a -> IO a) -> IO a
    forall a. (a -> IO a) -> IO a
    fixIO (\ a
    r -> IOEnv env a -> env -> IO a
    forall env a. IOEnv env a -> env -> IO a
    unIOEnv (a -> IOEnv env a
    f a
    r) env
    env))

    ---------------------------
    tryM :: IOEnv env r -> IOEnv env (Either IOEnvFailure r)
    -- Reflect UserError exceptions (only) into IOEnv monad
    -- Other exceptions are not caught; they are simply propagated as exns
    --
    -- The idea is that errors in the program being compiled will give rise
    -- to UserErrors.  But, say, pattern-match failures in GHC itself should
    -- not be caught here, else they'll be reported as errors in the program
    -- begin compiled!
    tryM :: forall env r. IOEnv env r -> IOEnv env (Either IOEnvFailure r)
    tryM (IOEnv env -> IO r
    thing) = (env -> IO (Either IOEnvFailure r))
    -> IOEnv env (Either IOEnvFailure r)
    forall env a. (env -> IO a) -> IOEnv env a
    IOEnv (\ env
    env -> IO r -> IO (Either IOEnvFailure r)
    forall a. IO a -> IO (Either IOEnvFailure a)
    tryIOEnvFailure (env -> IO r
    thing env
    env))

    tryIOEnvFailure :: IO a -> IO (Either IOEnvFailure a)
    tryIOEnvFailure :: forall a. IO a -> IO (Either IOEnvFailure a)
    tryIOEnvFailure = IO a -> IO (Either IOEnvFailure a)
    forall e a. Exception e => IO a -> IO (Either e a)
    try

    tryAllM :: IOEnv env r -> IOEnv env (Either SomeException r)
    -- Catch *all* synchronous exceptions
    -- This is used when running a Template-Haskell splice, when
    -- even a pattern-match failure is a programmer error
    tryAllM :: forall env r. IOEnv env r -> IOEnv env (Either SomeException r)
    tryAllM (IOEnv env -> IO r
    thing) = (env -> IO (Either SomeException r))
    -> IOEnv env (Either SomeException r)
    forall env a. (env -> IO a) -> IOEnv env a
    IOEnv (\ env
    env -> IO r -> IO (Either SomeException r)
    forall a. IO a -> IO (Either SomeException a)
    safeTry (env -> IO r
    thing env
    env))

    -- | Like 'try', but doesn't catch asynchronous exceptions
    safeTry :: IO a -> IO (Either SomeException a)
    safeTry :: forall a. IO a -> IO (Either SomeException a)
    safeTry IO a
    act = do
      var <- IO (MVar (Either SomeException a))
    forall a. IO (MVar a)
    newEmptyMVar
      -- uninterruptible because we want to mask around 'killThread', which is interruptible.
      uninterruptibleMask $ \forall a. IO a -> IO a
    restore -> do
        -- Fork, so that 'act' is safe from all asynchronous exceptions other than the ones we send it
        t <- IO () -> IO ThreadId
    forkIO (IO () -> IO ThreadId) -> IO () -> IO ThreadId
    forall a b. (a -> b) -> a -> b
    $ IO a -> IO (Either SomeException a)
    forall e a. Exception e => IO a -> IO (Either e a)
    try (IO a -> IO a
    forall a. IO a -> IO a
    restore IO a
    act) IO (Either SomeException a)
    -> (Either SomeException a -> IO ()) -> IO ()
    forall a b. IO a -> (a -> IO b) -> IO b
    forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
    >>= MVar (Either SomeException a) -> Either SomeException a -> IO ()
    forall a. MVar a -> a -> IO ()
    putMVar MVar (Either SomeException a)
    var
        restore (readMVar var)
          `catchException` \(SomeException
    e :: SomeException) -> do
            -- Control reaches this point only if the parent thread was sent an async exception
            -- In that case, kill the 'act' thread and re-raise the exception
            ThreadId -> IO ()
    killThread ThreadId
    t
            SomeException -> IO (Either SomeException a)
    forall e a. (HasCallStack, Exception e) => e -> IO a
    throwIO SomeException
    e

    tryMostM :: IOEnv env r -> IOEnv env (Either SomeException r)
    tryMostM :: forall env r. IOEnv env r -> IOEnv env (Either SomeException r)
    tryMostM (IOEnv env -> IO r
    thing) = (env -> IO (Either SomeException r))
    -> IOEnv env (Either SomeException r)
    forall env a. (env -> IO a) -> IOEnv env a
    IOEnv (\ env
    env -> IO r -> IO (Either SomeException r)
    forall a. IO a -> IO (Either SomeException a)
    tryMost (env -> IO r
    thing env
    env))

    ---------------------------
    unsafeInterleaveM :: IOEnv env a -> IOEnv env a
    unsafeInterleaveM :: forall env a. IOEnv env a -> IOEnv env a
    unsafeInterleaveM (IOEnv env -> IO a
    m) = (env -> IO a) -> IOEnv env a
    forall env a. (env -> IO a) -> IOEnv env a
    IOEnv (\ env
    env -> IO a -> IO a
    forall a. IO a -> IO a
    unsafeInterleaveIO (env -> IO a
    m env
    env))

    uninterruptibleMaskM_ :: IOEnv env a -> IOEnv env a
    uninterruptibleMaskM_ :: forall env a. IOEnv env a -> IOEnv env a
    uninterruptibleMaskM_ (IOEnv env -> IO a
    m) = (env -> IO a) -> IOEnv env a
    forall env a. (env -> IO a) -> IOEnv env a
    IOEnv (\ env
    env -> IO a -> IO a
    forall a. IO a -> IO a
    uninterruptibleMask_ (env -> IO a
    m env
    env))

    ----------------------------------------------------------------------
    -- Alternative/MonadPlus
    ----------------------------------------------------------------------

    instance Alternative (IOEnv env) where
        empty :: forall a. IOEnv env a
    empty   = (env -> IO a) -> IOEnv env a
    forall env a. (env -> IO a) -> IOEnv env a
    IOEnv (IO a -> env -> IO a
    forall a b. a -> b -> a
    const IO a
    forall a. IO a
    forall (f :: * -> *) a. Alternative f => f a
    empty)
        IOEnv env a
    m <|> :: forall a. IOEnv env a -> IOEnv env a -> IOEnv env a
    <|> IOEnv env a
    n = (env -> IO a) -> IOEnv env a
    forall env a. (env -> IO a) -> IOEnv env a
    IOEnv (\env
    env -> IOEnv env a -> env -> IO a
    forall env a. IOEnv env a -> env -> IO a
    unIOEnv IOEnv env a
    m env
    env IO a -> IO a -> IO a
    forall a. IO a -> IO a -> IO a
    forall (f :: * -> *) a. Alternative f => f a -> f a -> f a
    <|> IOEnv env a -> env -> IO a
    forall env a. IOEnv env a -> env -> IO a
    unIOEnv IOEnv env a
    n env
    env)

    instance MonadPlus (IOEnv env)

    ----------------------------------------------------------------------
    -- Accessing input/output
    ----------------------------------------------------------------------

    newMutVar :: a -> IOEnv env (IORef a)
    newMutVar :: forall a env. a -> IOEnv env (IORef a)
    newMutVar a
    val = IO (IORef a) -> IOEnv env (IORef a)
    forall a. IO a -> IOEnv env a
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO (a -> IO (IORef a)
    forall a. a -> IO (IORef a)
    newIORef a
    val)

    writeMutVar :: IORef a -> a -> IOEnv env ()
    writeMutVar :: forall a env. IORef a -> a -> IOEnv env ()
    writeMutVar IORef a
    var a
    val = IO () -> IOEnv env ()
    forall a. IO a -> IOEnv env a
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO (IORef a -> a -> IO ()
    forall a. IORef a -> a -> IO ()
    writeIORef IORef a
    var a
    val)

    readMutVar :: IORef a -> IOEnv env a
    readMutVar :: forall a env. IORef a -> IOEnv env a
    readMutVar IORef a
    var = IO a -> IOEnv env a
    forall a. IO a -> IOEnv env a
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO (IORef a -> IO a
    forall a. IORef a -> IO a
    readIORef IORef a
    var)

    updMutVar :: IORef a -> (a -> a) -> IOEnv env ()
    updMutVar :: forall a env. IORef a -> (a -> a) -> IOEnv env ()
    updMutVar IORef a
    var a -> a
    upd = IO () -> IOEnv env ()
    forall a. IO a -> IOEnv env a
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO (IORef a -> (a -> a) -> IO ()
    forall a. IORef a -> (a -> a) -> IO ()
    modifyIORef IORef a
    var a -> a
    upd)

    -- | Atomically update the reference.  Does not force the evaluation of the
    -- new variable contents.  For strict update, use 'atomicUpdMutVar''.
    atomicUpdMutVar :: IORef a -> (a -> (a, b)) -> IOEnv env b
    atomicUpdMutVar :: forall a b env. IORef a -> (a -> (a, b)) -> IOEnv env b
    atomicUpdMutVar IORef a
    var a -> (a, b)
    upd = IO b -> IOEnv env b
    forall a. IO a -> IOEnv env a
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO (IORef a -> (a -> (a, b)) -> IO b
    forall a b. IORef a -> (a -> (a, b)) -> IO b
    atomicModifyIORef IORef a
    var a -> (a, b)
    upd)

    -- | Strict variant of 'atomicUpdMutVar'.
    atomicUpdMutVar' :: IORef a -> (a -> (a, b)) -> IOEnv env b
    atomicUpdMutVar' :: forall a b env. IORef a -> (a -> (a, b)) -> IOEnv env b
    atomicUpdMutVar' IORef a
    var a -> (a, b)
    upd = IO b -> IOEnv env b
    forall a. IO a -> IOEnv env a
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
    liftIO (IORef a -> (a -> (a, b)) -> IO b
    forall a b. IORef a -> (a -> (a, b)) -> IO b
    atomicModifyIORef' IORef a
    var a -> (a, b)
    upd)

    ----------------------------------------------------------------------
    -- Accessing the environment
    ----------------------------------------------------------------------

    getEnv :: IOEnv env env
    {-# INLINE getEnv #-}
    getEnv :: forall env. IOEnv env env
    getEnv = (env -> IO env) -> IOEnv env env
    forall env a. (env -> IO a) -> IOEnv env a
    IOEnv (\ env
    env -> env -> IO env
    forall a. a -> IO a
    forall (m :: * -> *) a. Monad m => a -> m a
    return env
    env)

    -- | Perform a computation with a different environment
    setEnv :: env' -> IOEnv env' a -> IOEnv env a
    {-# INLINE setEnv #-}
    setEnv :: forall env' a env. env' -> IOEnv env' a -> IOEnv env a
    setEnv env'
    new_env (IOEnv env' -> IO a
    m) = (env -> IO a) -> IOEnv env a
    forall env a. (env -> IO a) -> IOEnv env a
    IOEnv (\ env
    _ -> env' -> IO a
    m env'
    new_env)

    -- | Perform a computation with an altered environment
    updEnv :: (env -> env') -> IOEnv env' a -> IOEnv env a
    {-# INLINE updEnv #-}
    updEnv :: forall env env' a. (env -> env') -> IOEnv env' a -> IOEnv env a
    updEnv env -> env'
    upd (IOEnv env' -> IO a
    m) = (env -> IO a) -> IOEnv env a
    forall env a. (env -> IO a) -> IOEnv env a
    IOEnv (\ env
    env -> env' -> IO a
    m (env -> env'
    upd env
    env))