- -- Getting at the environment
- getEnv, setEnv, updEnv,
+ -- Getting at the environment
+ getEnv, setEnv, updEnv,
- runIOEnv, unsafeInterleaveM,
- tryM, tryAllM, tryMostM, fixM,
+ runIOEnv, unsafeInterleaveM,
+ tryM, tryAllM, tryMostM, fixM,
- -- I/O operations
- IORef, newMutVar, readMutVar, writeMutVar, updMutVar
+ -- I/O operations
+ IORef, newMutVar, readMutVar, writeMutVar, updMutVar,
+ atomicUpdMutVar, atomicUpdMutVar'
-import Data.IORef ( IORef, newIORef, readIORef, writeIORef, modifyIORef )
-import System.IO.Unsafe ( unsafeInterleaveIO )
-import System.IO ( fixIO )
+import Data.IORef ( IORef, newIORef, readIORef, writeIORef, modifyIORef,
+ atomicModifyIORef )
+import Data.Typeable
+import System.IO.Unsafe ( unsafeInterleaveIO )
+import System.IO ( fixIO )
+import Control.Monad
-- 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
-- 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
-tryAllM :: IOEnv env r -> IOEnv env (Either Exception r)
+tryIOEnvFailure :: IO a -> IO (Either IOEnvFailure a)
+tryIOEnvFailure = try
+
+-- XXX We shouldn't be catching everything, e.g. timeouts
+tryAllM :: IOEnv env r -> IOEnv env (Either SomeException r)
-- Catch *all* exceptions
-- This is used when running a Template-Haskell splice, when
-- even a pattern-match failure is a programmer error
tryAllM (IOEnv thing) = IOEnv (\ env -> try (thing env))
-- Catch *all* exceptions
-- This is used when running a Template-Haskell splice, when
-- even a pattern-match failure is a programmer error
tryAllM (IOEnv thing) = IOEnv (\ env -> try (thing env))
--- Accessing input/output
+-- MonadPlus
+----------------------------------------------------------------------
+
+-- For use if the user has imported Control.Monad.Error from MTL
+-- Requires UndecidableInstances
+instance MonadPlus IO => MonadPlus (IOEnv env) where
+ mzero = IOEnv (const mzero)
+ m `mplus` n = IOEnv (\env -> unIOEnv m env `mplus` unIOEnv n env)
+
+----------------------------------------------------------------------
+-- Accessing input/output
+-- | 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 var upd = liftIO (atomicModifyIORef var upd)
+
+-- | Strict variant of 'atomicUpdMutVar'.
+atomicUpdMutVar' :: IORef a -> (a -> (a, b)) -> IOEnv env b
+atomicUpdMutVar' var upd = do
+ r <- atomicUpdMutVar var upd
+ _ <- liftIO . evaluate =<< readMutVar var
+ return r
-{-# -- SPECIALIZE mapM :: (a -> IOEnv env b) -> [a] -> IOEnv env [b] #-}
-{-# -- SPECIALIZE mapM_ :: (a -> IOEnv env b) -> [a] -> IOEnv env () #-}
-{-# -- SPECIALIZE mapSndM :: (b -> IOEnv env c) -> [(a,b)] -> IOEnv env [(a,c)] #-}
-{-# -- SPECIALIZE sequence :: [IOEnv env a] -> IOEnv env [a] #-}
-{-# -- SPECIALIZE sequence_ :: [IOEnv env a] -> IOEnv env () #-}
-{-# -- SPECIALIZE foldlM :: (a -> b -> IOEnv env a) -> a -> [b] -> IOEnv env a #-}
-{-# -- SPECIALIZE foldrM :: (b -> a -> IOEnv env a) -> a -> [b] -> IOEnv env a #-}
-{-# -- SPECIALIZE mapAndUnzipM :: (a -> IOEnv env (b,c)) -> [a] -> IOEnv env ([b],[c]) #-}
-{-# -- SPECIALIZE mapAndUnzip3M :: (a -> IOEnv env (b,c,d)) -> [a] -> IOEnv env ([b],[c],[d]) #-}
-{-# -- SPECIALIZE zipWithM :: (a -> b -> IOEnv env c) -> [a] -> [b] -> IOEnv env [c] #-}
-{-# -- SPECIALIZE zipWithM_ :: (a -> b -> IOEnv env c) -> [a] -> [b] -> IOEnv env () #-}
-{-# -- SPECIALIZE anyM :: (a -> IOEnv env Bool) -> [a] -> IOEnv env Bool #-}
-{-# -- SPECIALIZE when :: Bool -> IOEnv env a -> IOEnv env () #-}
-{-# -- SPECIALIZE unless :: Bool -> IOEnv env a -> IOEnv env () #-}
+-- {-# SPECIALIZE mapM :: (a -> IOEnv env b) -> [a] -> IOEnv env [b] #-}
+-- {-# SPECIALIZE mapM_ :: (a -> IOEnv env b) -> [a] -> IOEnv env () #-}
+-- {-# SPECIALIZE mapSndM :: (b -> IOEnv env c) -> [(a,b)] -> IOEnv env [(a,c)] #-}
+-- {-# SPECIALIZE sequence :: [IOEnv env a] -> IOEnv env [a] #-}
+-- {-# SPECIALIZE sequence_ :: [IOEnv env a] -> IOEnv env () #-}
+-- {-# SPECIALIZE foldlM :: (a -> b -> IOEnv env a) -> a -> [b] -> IOEnv env a #-}
+-- {-# SPECIALIZE foldrM :: (b -> a -> IOEnv env a) -> a -> [b] -> IOEnv env a #-}
+-- {-# SPECIALIZE mapAndUnzipM :: (a -> IOEnv env (b,c)) -> [a] -> IOEnv env ([b],[c]) #-}
+-- {-# SPECIALIZE mapAndUnzip3M :: (a -> IOEnv env (b,c,d)) -> [a] -> IOEnv env ([b],[c],[d]) #-}
+-- {-# SPECIALIZE zipWithM :: (a -> b -> IOEnv env c) -> [a] -> [b] -> IOEnv env [c] #-}
+-- {-# SPECIALIZE zipWithM_ :: (a -> b -> IOEnv env c) -> [a] -> [b] -> IOEnv env () #-}
+-- {-# SPECIALIZE anyM :: (a -> IOEnv env Bool) -> [a] -> IOEnv env Bool #-}
+-- {-# SPECIALIZE when :: Bool -> IOEnv env a -> IOEnv env () #-}
+-- {-# SPECIALIZE unless :: Bool -> IOEnv env a -> IOEnv env () #-}