pugs-compat-0.0.6.2: src/Pugs/Compat/Monads.hs
module Pugs.Compat.Monads (
internalError,
fatalError,
traceM,
warn,
die,
fmapM,
fmapM_,
combine,
modifyTVar,
inlinePerformIO,
inlinePerformSTM,
unsafePerformSTM,
maybeM, finallyM,
catchIO, evaluateIO
) where
import Prelude hiding (mapM)
import Data.Traversable
import Debug.Trace
import qualified Data.ByteString.Internal as I (inlinePerformIO)
import System.Exit
import System.IO (hPutStrLn, stderr)
import System.IO.Unsafe
import Control.Exception (Exception(..))
import Control.Concurrent.STM
import Control.Monad.Trans (MonadIO(..))
import qualified Control.Exception (catch, evaluate)
{-|
Compose a list of @(a -> a)@ transformer functions into a single chained
function, using @foldr@ via the @(.)@ operator.
Note that the transformations are applied to the eventual argument in
right-to-left order.
-}
combine :: [a -> a] -- ^ List of transformer functions
-> (a -> a) -- ^ The final combined transformer
combine = foldr (.) id
{-# INLINE inlinePerformIO #-}
inlinePerformIO :: IO a -> a
inlinePerformIO = I.inlinePerformIO
{-# INLINE inlinePerformSTM #-}
inlinePerformSTM :: STM a -> a
inlinePerformSTM m = I.inlinePerformIO (atomically m)
{-# NOINLINE unsafePerformSTM #-}
unsafePerformSTM :: STM a -> a
unsafePerformSTM m = unsafePerformIO (atomically m)
{-|
Read an STM variable, apply some transformation function to it, and write the
transformed value back to the same variable.
-}
modifyTVar :: TVar a
-> (a -> a)
-> STM ()
modifyTVar var f = do
x <- readTVar var
writeTVar var (f x)
-- instance MonadIO STM where
-- liftIO = unsafeIOToSTM
{-|
Extract a @Maybe@ value from the first argument (a monad).
If it's a @Just@ (i.e. it contains a value), apply the second argument
(a monad-producing function) to it, and @return@ the contents of /that/
wrapped in a @Just@.
Otherwise, merely @return Nothing@.
(Strictly speaking, this function can operate with any @FunctorM@, not just
@Maybe@, but it helps to have a concrete example to explain things.)
-}
maybeM :: (Traversable f, Monad m)
=> m (f a) -- ^ A @Maybe@ value encapsulated in a monad
-> (a -> m b) -- ^ Action to perform on the first arg /if/ it contains
-- a value
-> m (f b) -- ^ Monad containing (@Just@ /result/) or @Nothing@
maybeM f m = mapM m =<< f
catchIO :: Exception e => forall a. IO a -> (e -> IO a) -> IO a
catchIO = Control.Exception.catch
evaluateIO :: a -> IO a
evaluateIO = Control.Exception.evaluate
{-# INLINE finallyM #-}
finallyM :: (Monad m)
=> m a -- ^ The actual action
-> m b -- ^ the finalizer
-> m a -- ^ Result of the actual action
finallyM ma mb = do
r <- ma
mb
return r
internalError :: String -> a
internalError s = error $
"Internal error:\n " ++ s ++ "\nPlease file a bug report."
fatalError :: (MonadIO m, Show a) => String -> a -> m b
fatalError x y = do
warn x y
liftIO $ exitFailure
die :: (Monad m, Show a) => String -> a -> m b
die str a = fail $ str ++ ": " ++ show a
warn :: (MonadIO m, Show a) => String -> a -> m ()
warn str val = liftIO $ do
hPutStrLn stderr $ "*** " ++ str ++ ":\n " ++ show val
-- | This is just @Debug.Trace.trace@, but allows for cleaner code in do blocks.
traceM :: Monad m => String -> m ()
traceM s = trace s $ return ()
fmapM :: (Functor t, Traversable t, Monad m) => (a -> m b) -> t a -> m (t b)
fmapM = mapM
fmapM_ :: (Functor t, Traversable t, Monad m) => (a -> m b) -> t a -> m ()
fmapM_ f x = mapM f x >> return ()