-- Hoogle documentation, generated by Haddock -- See Hoogle, http://www.haskell.org/hoogle/ -- | Exceptions, with checkpoints and context. -- -- Please see the README on Github at -- https://github.com/parsonsmatt/annotated-exception#readme @package annotated-exception @version 0.3.0.2 -- | An Annotation is attached to an AnnotatedException. -- They're essentially a dynamically typed value with a convenient -- IsString instance. -- -- When integrating into your own application, you will likely want to do -- more than just have the String you get from showing the -- Annotation. You can do this by creating a special wrapper type -- that carries a class constraint. This allows you to also pluck out the -- Annotations from your library or executable independently and -- treat them differently from unknonwn annotations. -- -- As an example, here's one that requires a ToJSON constraint on -- the underlying value. This means that you can convert any annotated -- value to JSON, and then use that JSON in bug reports or logging. -- --
-- data JsonAnnotation where
-- JsonAnnotation :: (ToJSON a, Typeable a) => a -> JsonAnnotation
--
-- instance Show JsonANnotation where
-- show (JsonAnnotation a) = concat
-- [ "(JsonAnnotation ("
-- , show (toJSON a)
-- , "))"
-- ]
--
-- jsonCheckpoint :: (Typeable a, ToJSON a, HasCallStack, MonadCatch m) => a -> m a -> m a
-- jsonCheckpoint val = withFrozenCallStack checkpoint (JsonAnnotation val)
--
--
-- When handling the [Annotation] carried on the
-- AnnotatedException, you can use tryAnnotations to pick
-- out the JSON annotations.
--
-- -- jsonAnnotations :: [Annotation] -> ([JsonAnnotation], [Annotation]) -- jsonAnnotations = tryAnnotations ---- -- and handle them however you please. module Data.Annotation -- | An Annotation is a wrapper around a value that includes a -- Typeable constraint so we can later unpack it. It is -- essentially a Dynamic, but we also include Show so that -- you can always fall back to simply showing the -- Annotation if it is otherwise unrecognized. data Annotation [Annotation] :: AnnC a => a -> Annotation -- | A wrapper type for putting a CallStack into an -- Annotation. We need this because CallStack does not have -- an Eq instance. -- -- Deprecated in 0.2.0.0 since you can just put a CallStack -- directly in an Annotation now that we have no need for an -- Eq constraint on it. -- | Deprecated: You can just use CallStack directly now. newtype CallStackAnnotation -- | Deprecated: You can just use CallStack directly now. CallStackAnnotation :: [(String, SrcLoc)] -> CallStackAnnotation [unCallStackAnnotation] :: CallStackAnnotation -> [(String, SrcLoc)] -- | The constraints that the value inside an Annotation must have. -- -- We want Typeable so we can do cast and potentially get -- more useful information out of it. type AnnC a = (Typeable a, Show a) -- | Wrap a value in an Annotation. toAnnotation :: AnnC a => a -> Annotation -- | Attempt to cast the underlying value out of an -- Annotation. castAnnotation :: forall a. Typeable a => Annotation -> Maybe a -- | Attempt to cast the underlying value out of an -- Annotation. Returns the original Annotation if the cast -- isn't right. tryAnnotation :: forall a. Typeable a => Annotation -> Either a Annotation -- | Attempt to cast list of Annotation into the given type. -- Any Annotation that is not in that form is left untouched. tryAnnotations :: forall a. Typeable a => [Annotation] -> ([a], [Annotation]) -- | Returns the Set of types that are in the given annotations. annotationTypes :: [Annotation] -> Set TypeRep -- | Map a function over the given Annotation. If the types don't -- match up, then the whole thing returns Nothing. mapAnnotation :: (AnnC a, AnnC b) => (a -> b) -> Annotation -> Maybe Annotation -- | Map a function over the Annotation, leaving it unchanged if the -- types don't match. mapMaybeAnnotation :: (AnnC a, AnnC b) => (a -> b) -> Annotation -> Annotation -- | Grab an Annotation corresponding to the CallStack that -- is currently in scope. callStackAnnotation :: HasCallStack => Annotation -- | Stuff a CallStack into an Annotation via the -- CallStackAnnotation newtype wrapper. callStackToAnnotation :: CallStack -> Annotation -- | Convert the legacy CallStackAnnotation into a CallStack. -- -- Deprecated in 0.2.0.0 since you can use CallStack directly. -- | Deprecated: You can use CallStack directly in annotations as -- of 0.2.0.0. callStackFromAnnotation :: CallStackAnnotation -> CallStack -- | Extract the CallStacks from the [Annotation]. -- Any Annotation not corresponding to a CallStack will be -- in the second element of the tuple. -- | Deprecated: You can just use tryAnnotations directly as of -- 0.2.0.0. callStackInAnnotations :: [Annotation] -> ([CallStack], [Annotation]) instance GHC.Show.Show Data.Annotation.CallStackAnnotation instance GHC.Classes.Eq Data.Annotation.CallStackAnnotation instance GHC.Show.Show Data.Annotation.Annotation instance Data.String.IsString Data.Annotation.Annotation -- | This module defines an exception wrapper AnnotatedException -- that carries a list of Annotations, along with some helper -- methods for throwing and catching that can make the annotations -- transparent. -- -- While this library can be used directly, it is recommended that you -- define your own types and functions specific to your domain. As an -- example, checkpoint is useful *only* for providing exception -- annotation information. However, you probably want to use -- checkpoint in concert with other context adding features, like -- logging. -- -- Likewise, the Annotation type defined in Data.Annotation -- is essentially a wrapper for a dynamically typed value. So you -- probably want to define your own checkpoint that uses a custom -- type that you want to enforce throughout your application. module Control.Exception.Annotated -- | The AnnotatedException type wraps an exception with a -- [Annotation]. This can provide a sort of a manual -- stack trace with programmer provided data. data AnnotatedException exception AnnotatedException :: [Annotation] -> exception -> AnnotatedException exception [annotations] :: AnnotatedException exception -> [Annotation] [exception] :: AnnotatedException exception -> exception -- | Annotate the underlying exception with a CallStack. exceptionWithCallStack :: (Exception e, HasCallStack) => e -> AnnotatedException e -- | Throws an Exception and annotates it with the current -- CallStack. -- -- An alias for throwWithCallStack. throw :: (HasCallStack, MonadThrow m, Exception e) => e -> m a -- | Attaches the CallStack to the AnnotatedException that is -- thrown. throwWithCallStack :: (HasCallStack, MonadThrow m, Exception e) => e -> m a -- | Add a single Annotation to any exceptions thrown in the -- following action. The CallStack present on any -- AnnotatedException will also be updated to include this -- location. -- -- Example: -- --
-- main = do -- checkpoint "Foo" $ do -- print =<< readFile "I don't exist.markdown" ---- -- The exception thrown due to a missing file will now have an -- Annotation Foo. checkpoint :: (HasCallStack, MonadCatch m) => Annotation -> m a -> m a -- | Add the list of Annotation to any exception thrown in the -- following action. checkpointMany :: (MonadCatch m, HasCallStack) => [Annotation] -> m a -> m a -- | Adds only the current CallStack to the checkpoint. This -- function searches any thrown exception for a pre-existing -- CallStack and will merge the given pre-existing -- CallStack with the one on this function, in an attempt to -- preserve the actual call history. checkpointCallStack :: (MonadCatch m, HasCallStack) => m a -> m a -- | Add the current CallStack to the checkpoint, along with the -- given annotations. This function merges CallStacks together, -- attempting to preserve the call site ordering as GHC does it. -- -- As of 0.2.0.0, an alias for checkpointMany. -- | Deprecated: As of 0.2.0.0 this is exactly equivalent to -- checkpointMany. checkpointCallStackWith :: (MonadCatch m, HasCallStack) => [Annotation] -> m a -> m a -- | Catch an exception. This works just like catch, but it also -- will attempt to catch AnnotatedException e. The -- annotations will be preserved in the handler, so rethrowing exceptions -- will retain the context. -- -- Let's consider a few examples, that share this import and exception -- type. -- --
-- import qualified Control.Exception.Safe as Safe -- import Control.Exception.Annotated -- -- data TestException deriving (Show, Exception) ---- -- We can throw an exception and catch it as usual. -- --
-- throw TestException `catch` \TestException -> -- putStrLn "ok!" ---- -- We can throw an exception and catch it with annotations. -- --
-- throw TestException `catch` \(AnnotatedException anns TestException) -> -- putStrLn "ok!" ---- -- We can throw an exception and catch it as a -- AnnotatedException SomeException. -- --
-- throw TestException `catch` \(AnnotatedException anns (e :: SomeException) -> -- putStrLn "ok!" --catch :: (HasCallStack, Exception e, MonadCatch m) => m a -> (e -> m a) -> m a -- | Like catches, but this function enhance the provided -- Handlers to "see through" any AnnotatedExceptions. catches :: (MonadCatch m, HasCallStack) => m a -> [Handler m a] -> m a -- | Like catch, but always returns a AnnotatedException. tryAnnotated :: (Exception e, MonadCatch m) => m a -> m (Either (AnnotatedException e) a) -- | Like try, but can also handle an AnnotatedException or -- the underlying value. Useful when you want to try to catch a -- type of exception, but you may not care about the Annotations -- that it may or may not have. -- -- Example: -- --
-- Left exn <- try $ throw (AnnotatedException [] TestException) -- exn == TestException ---- --
-- Left exn <- try $ throw TestException -- exn == AnnotatedException [] TestException --try :: (Exception e, MonadCatch m) => m a -> m (Either e a) -- | Call fromException on the underlying Exception, -- attaching the annotations to the result. check :: Exception e => AnnotatedException SomeException -> Maybe (AnnotatedException e) -- | Call toException on the underlying Exception. hide :: Exception e => AnnotatedException e -> AnnotatedException SomeException -- | Retrieves the CallStack from an AnnotatedException if -- one is present. -- -- The library maintains an internal check that a single CallStack -- is present in the list, so this only returns the first one found. If -- you have added a CallStack directly to the -- [Annotation], then this will likely break. annotatedExceptionCallStack :: AnnotatedException exception -> Maybe CallStack -- | Adds a CallStack to the given AnnotatedException. This -- function will search through the existing annotations, and it will not -- add a second CallStack to the list. Instead, it will append the -- contents of the given CallStack to the existing one. -- -- This mirrors the behavior of the way HasCallStack actually -- works. addCallStackToException :: CallStack -> AnnotatedException exception -> AnnotatedException exception -- | An Annotation is a wrapper around a value that includes a -- Typeable constraint so we can later unpack it. It is -- essentially a Dynamic, but we also include Show so that -- you can always fall back to simply showing the -- Annotation if it is otherwise unrecognized. data Annotation [Annotation] :: AnnC a => a -> Annotation -- | A wrapper type for putting a CallStack into an -- Annotation. We need this because CallStack does not have -- an Eq instance. -- -- Deprecated in 0.2.0.0 since you can just put a CallStack -- directly in an Annotation now that we have no need for an -- Eq constraint on it. -- | Deprecated: You can just use CallStack directly now. newtype CallStackAnnotation -- | Deprecated: You can just use CallStack directly now. CallStackAnnotation :: [(String, SrcLoc)] -> CallStackAnnotation [unCallStackAnnotation] :: CallStackAnnotation -> [(String, SrcLoc)] -- | Any type that you wish to throw or catch as an exception must be an -- instance of the Exception class. The simplest case is a new -- exception type directly below the root: -- --
-- data MyException = ThisException | ThatException -- deriving Show -- -- instance Exception MyException ---- -- The default method definitions in the Exception class do what -- we need in this case. You can now throw and catch -- ThisException and ThatException as exceptions: -- --
-- *Main> throw ThisException `catch` \e -> putStrLn ("Caught " ++ show (e :: MyException))
-- Caught ThisException
--
--
-- In more complicated examples, you may wish to define a whole hierarchy
-- of exceptions:
--
-- -- --------------------------------------------------------------------- -- -- Make the root exception type for all the exceptions in a compiler -- -- data SomeCompilerException = forall e . Exception e => SomeCompilerException e -- -- instance Show SomeCompilerException where -- show (SomeCompilerException e) = show e -- -- instance Exception SomeCompilerException -- -- compilerExceptionToException :: Exception e => e -> SomeException -- compilerExceptionToException = toException . SomeCompilerException -- -- compilerExceptionFromException :: Exception e => SomeException -> Maybe e -- compilerExceptionFromException x = do -- SomeCompilerException a <- fromException x -- cast a -- -- --------------------------------------------------------------------- -- -- Make a subhierarchy for exceptions in the frontend of the compiler -- -- data SomeFrontendException = forall e . Exception e => SomeFrontendException e -- -- instance Show SomeFrontendException where -- show (SomeFrontendException e) = show e -- -- instance Exception SomeFrontendException where -- toException = compilerExceptionToException -- fromException = compilerExceptionFromException -- -- frontendExceptionToException :: Exception e => e -> SomeException -- frontendExceptionToException = toException . SomeFrontendException -- -- frontendExceptionFromException :: Exception e => SomeException -> Maybe e -- frontendExceptionFromException x = do -- SomeFrontendException a <- fromException x -- cast a -- -- --------------------------------------------------------------------- -- -- Make an exception type for a particular frontend compiler exception -- -- data MismatchedParentheses = MismatchedParentheses -- deriving Show -- -- instance Exception MismatchedParentheses where -- toException = frontendExceptionToException -- fromException = frontendExceptionFromException ---- -- We can now catch a MismatchedParentheses exception as -- MismatchedParentheses, SomeFrontendException or -- SomeCompilerException, but not other types, e.g. -- IOException: -- --
-- *Main> throw MismatchedParentheses `catch` \e -> putStrLn ("Caught " ++ show (e :: MismatchedParentheses))
-- Caught MismatchedParentheses
-- *Main> throw MismatchedParentheses `catch` \e -> putStrLn ("Caught " ++ show (e :: SomeFrontendException))
-- Caught MismatchedParentheses
-- *Main> throw MismatchedParentheses `catch` \e -> putStrLn ("Caught " ++ show (e :: SomeCompilerException))
-- Caught MismatchedParentheses
-- *Main> throw MismatchedParentheses `catch` \e -> putStrLn ("Caught " ++ show (e :: IOException))
-- *** Exception: MismatchedParentheses
--
class (Typeable e, Show e) => Exception e
toException :: Exception e => e -> SomeException
fromException :: Exception e => SomeException -> Maybe e
-- | Render this exception value in a human-friendly manner.
--
-- Default implementation: show.
displayException :: Exception e => e -> String
-- | The SomeException type is the root of the exception type
-- hierarchy. When an exception of type e is thrown, behind the
-- scenes it is encapsulated in a SomeException.
data () => SomeException
SomeException :: e -> SomeException
-- | Generalized version of Handler
data () => Handler (m :: Type -> Type) a
Handler :: (e -> m a) -> Handler (m :: Type -> Type) a
instance Data.Traversable.Traversable Control.Exception.Annotated.AnnotatedException
instance Data.Foldable.Foldable Control.Exception.Annotated.AnnotatedException
instance GHC.Base.Functor Control.Exception.Annotated.AnnotatedException
instance GHC.Exception.Type.Exception exception => GHC.Show.Show (Control.Exception.Annotated.AnnotatedException exception)
instance GHC.Base.Applicative Control.Exception.Annotated.AnnotatedException
instance GHC.Exception.Type.Exception exception => GHC.Exception.Type.Exception (Control.Exception.Annotated.AnnotatedException exception)
-- | This module presents the same interface as
-- Control.Exception.Annotated, but uses MonadUnliftIO
-- instead of MonadCatch or MonadThrow.
module Control.Exception.Annotated.UnliftIO
-- | The AnnotatedException type wraps an exception with a
-- [Annotation]. This can provide a sort of a manual
-- stack trace with programmer provided data.
data AnnotatedException exception
AnnotatedException :: [Annotation] -> exception -> AnnotatedException exception
[annotations] :: AnnotatedException exception -> [Annotation]
[exception] :: AnnotatedException exception -> exception
-- | Annotate the underlying exception with a CallStack.
exceptionWithCallStack :: (Exception e, HasCallStack) => e -> AnnotatedException e
-- | Like throwWithCallStack, but uses MonadIO instead of
-- MonadThrow.
throwWithCallStack :: forall e m a. (MonadIO m, Exception e, HasCallStack) => e -> m a
-- | Like checkpoint, but uses MonadUnliftIO instead of
-- MonadCatch.
checkpoint :: forall m a. (MonadUnliftIO m, HasCallStack) => Annotation -> m a -> m a
-- | Like checkpointMany, but uses MonadUnliftIO instead of
-- MonadCatch.
checkpointMany :: forall m a. (MonadUnliftIO m, HasCallStack) => [Annotation] -> m a -> m a
-- | Like checkpointCallStack, but uses MonadUnliftIO instead
-- of MonadCatch.
checkpointCallStack :: forall m a. (MonadUnliftIO m, HasCallStack) => m a -> m a
-- | Like checkpointCallStackWith, but uses MonadUnliftIO
-- instead of MonadCatch.
--
-- Deprecated in 0.2.0.0 as it is now an alias for checkpointMany.
-- | Deprecated: As of annotated-exception-0.2.0.0, this is an alias for
-- checkpointMany
checkpointCallStackWith :: forall m a. (MonadUnliftIO m, HasCallStack) => [Annotation] -> m a -> m a
-- | Like catch, but uses MonadUnliftIO instead of
-- MonadCatch.
catch :: forall e m a. (MonadUnliftIO m, Exception e, HasCallStack) => m a -> (e -> m a) -> m a
-- | Like catches, bt uses MonadUnliftIO instead of
-- MonadCatch.
catches :: forall m a. (MonadUnliftIO m, HasCallStack) => m a -> [Handler m a] -> m a
-- | Like tryAnnotated but uses MonadUnliftIO instead of
-- MonadCatch.
tryAnnotated :: forall e m a. (MonadUnliftIO m, Exception e) => m a -> m (Either (AnnotatedException e) a)
-- | Like try but uses MonadUnliftIO instead of
-- MonadCatch.
try :: forall e m a. (MonadUnliftIO m, Exception e) => m a -> m (Either e a)
-- | Call fromException on the underlying Exception,
-- attaching the annotations to the result.
check :: Exception e => AnnotatedException SomeException -> Maybe (AnnotatedException e)
-- | Call toException on the underlying Exception.
hide :: Exception e => AnnotatedException e -> AnnotatedException SomeException
-- | Retrieves the CallStack from an AnnotatedException if
-- one is present.
--
-- The library maintains an internal check that a single CallStack
-- is present in the list, so this only returns the first one found. If
-- you have added a CallStack directly to the
-- [Annotation], then this will likely break.
annotatedExceptionCallStack :: AnnotatedException exception -> Maybe CallStack
-- | Adds a CallStack to the given AnnotatedException. This
-- function will search through the existing annotations, and it will not
-- add a second CallStack to the list. Instead, it will append the
-- contents of the given CallStack to the existing one.
--
-- This mirrors the behavior of the way HasCallStack actually
-- works.
addCallStackToException :: CallStack -> AnnotatedException exception -> AnnotatedException exception
-- | An Annotation is a wrapper around a value that includes a
-- Typeable constraint so we can later unpack it. It is
-- essentially a Dynamic, but we also include Show so that
-- you can always fall back to simply showing the
-- Annotation if it is otherwise unrecognized.
data Annotation
[Annotation] :: AnnC a => a -> Annotation
-- | A wrapper type for putting a CallStack into an
-- Annotation. We need this because CallStack does not have
-- an Eq instance.
--
-- Deprecated in 0.2.0.0 since you can just put a CallStack
-- directly in an Annotation now that we have no need for an
-- Eq constraint on it.
-- | Deprecated: You can just use CallStack directly now.
newtype CallStackAnnotation
-- | Deprecated: You can just use CallStack directly now.
CallStackAnnotation :: [(String, SrcLoc)] -> CallStackAnnotation
[unCallStackAnnotation] :: CallStackAnnotation -> [(String, SrcLoc)]
-- | Any type that you wish to throw or catch as an exception must be an
-- instance of the Exception class. The simplest case is a new
-- exception type directly below the root:
--
-- -- data MyException = ThisException | ThatException -- deriving Show -- -- instance Exception MyException ---- -- The default method definitions in the Exception class do what -- we need in this case. You can now throw and catch -- ThisException and ThatException as exceptions: -- --
-- *Main> throw ThisException `catch` \e -> putStrLn ("Caught " ++ show (e :: MyException))
-- Caught ThisException
--
--
-- In more complicated examples, you may wish to define a whole hierarchy
-- of exceptions:
--
-- -- --------------------------------------------------------------------- -- -- Make the root exception type for all the exceptions in a compiler -- -- data SomeCompilerException = forall e . Exception e => SomeCompilerException e -- -- instance Show SomeCompilerException where -- show (SomeCompilerException e) = show e -- -- instance Exception SomeCompilerException -- -- compilerExceptionToException :: Exception e => e -> SomeException -- compilerExceptionToException = toException . SomeCompilerException -- -- compilerExceptionFromException :: Exception e => SomeException -> Maybe e -- compilerExceptionFromException x = do -- SomeCompilerException a <- fromException x -- cast a -- -- --------------------------------------------------------------------- -- -- Make a subhierarchy for exceptions in the frontend of the compiler -- -- data SomeFrontendException = forall e . Exception e => SomeFrontendException e -- -- instance Show SomeFrontendException where -- show (SomeFrontendException e) = show e -- -- instance Exception SomeFrontendException where -- toException = compilerExceptionToException -- fromException = compilerExceptionFromException -- -- frontendExceptionToException :: Exception e => e -> SomeException -- frontendExceptionToException = toException . SomeFrontendException -- -- frontendExceptionFromException :: Exception e => SomeException -> Maybe e -- frontendExceptionFromException x = do -- SomeFrontendException a <- fromException x -- cast a -- -- --------------------------------------------------------------------- -- -- Make an exception type for a particular frontend compiler exception -- -- data MismatchedParentheses = MismatchedParentheses -- deriving Show -- -- instance Exception MismatchedParentheses where -- toException = frontendExceptionToException -- fromException = frontendExceptionFromException ---- -- We can now catch a MismatchedParentheses exception as -- MismatchedParentheses, SomeFrontendException or -- SomeCompilerException, but not other types, e.g. -- IOException: -- --
-- *Main> throw MismatchedParentheses `catch` \e -> putStrLn ("Caught " ++ show (e :: MismatchedParentheses))
-- Caught MismatchedParentheses
-- *Main> throw MismatchedParentheses `catch` \e -> putStrLn ("Caught " ++ show (e :: SomeFrontendException))
-- Caught MismatchedParentheses
-- *Main> throw MismatchedParentheses `catch` \e -> putStrLn ("Caught " ++ show (e :: SomeCompilerException))
-- Caught MismatchedParentheses
-- *Main> throw MismatchedParentheses `catch` \e -> putStrLn ("Caught " ++ show (e :: IOException))
-- *** Exception: MismatchedParentheses
--
class (Typeable e, Show e) => Exception e
toException :: Exception e => e -> SomeException
fromException :: Exception e => SomeException -> Maybe e
-- | Render this exception value in a human-friendly manner.
--
-- Default implementation: show.
displayException :: Exception e => e -> String
-- | The SomeException type is the root of the exception type
-- hierarchy. When an exception of type e is thrown, behind the
-- scenes it is encapsulated in a SomeException.
data () => SomeException
SomeException :: e -> SomeException
-- | Like throw, but uses MonadIO instead of
-- MonadThrow.
throw :: forall e m a. (MonadIO m, Exception e, HasCallStack) => e -> m a
-- | Generalized version of Handler
data () => Handler (m :: Type -> Type) a
Handler :: (e -> m a) -> Handler (m :: Type -> Type) a
-- | Monads in which IO computations may be embedded. Any monad
-- built by applying a sequence of monad transformers to the IO
-- monad will be an instance of this class.
--
-- Instances should satisfy the following laws, which state that
-- liftIO is a transformer of monads:
--
--
class Monad m => MonadIO (m :: Type -> Type)
-- | Lift a computation from the IO monad. This allows us to run IO
-- computations in any monadic stack, so long as it supports these kinds
-- of operations (i.e. IO is the base monad for the stack).
--
-- -- import Control.Monad.Trans.State -- from the "transformers" library -- -- printState :: Show s => StateT s IO () -- printState = do -- state <- get -- liftIO $ print state ---- -- Had we omitted liftIO, we would have ended up with -- this error: -- --
-- • Couldn't match type ‘IO’ with ‘StateT s IO’ -- Expected type: StateT s IO () -- Actual type: IO () ---- -- The important part here is the mismatch between StateT s IO -- () and IO (). -- -- Luckily, we know of a function that takes an IO a and -- returns an (m a): liftIO, enabling us to run -- the program and see the expected results: -- --
-- > evalStateT printState "hello" -- "hello" -- -- > evalStateT printState 3 -- 3 --liftIO :: MonadIO m => IO a -> m a -- | Monads which allow their actions to be run in IO. -- -- While MonadIO allows an IO action to be lifted into -- another monad, this class captures the opposite concept: allowing you -- to capture the monadic context. Note that, in order to meet the laws -- given below, the intuition is that a monad must have no monadic state, -- but may have monadic context. This essentially limits -- MonadUnliftIO to ReaderT and IdentityT -- transformers on top of IO. -- -- Laws. For any function run provided by withRunInIO, it -- must meet the monad transformer laws as reformulated for -- MonadUnliftIO: -- --
run . return = return
run (m >>= f) = run m >>= run . f
-- withRunInIO inner = -- StateT $ \s -> -- withRunInIO $ \run -> -- inner (run . flip evalStateT s) ---- -- This breaks the identity law because the inner run m would -- throw away any state changes in m. class MonadIO m => MonadUnliftIO (m :: Type -> Type) -- | Convenience function for capturing the monadic context and running an -- IO action with a runner function. The runner function is used -- to run a monadic action m in IO. withRunInIO :: MonadUnliftIO m => ((forall a. () => m a -> IO a) -> IO b) -> m b