lio-0.11.6.0: Labeled IO Information Flow Control Library

Safe HaskellTrustworthy
LanguageHaskell98

LIO.Exception

Description

Exception routines much like the IO ones in Control.Exception (we duplicate the documentation below). There are two differences, however. First, LIO does not allow masking of asynchronous exceptions (since these are relied upon to kill a misbehaving thread). Hence, routines like onException are not guaranteed to run if a thread is unconditionally killed. Second, in a few cases (such as lWait) it is possible for the current label to be raised above the current clearance as an exception is thrown, in which case these functions do not catch the exception, either, since code cannot run under such circumstances.

Synopsis

Documentation

class (Typeable * e, Show e) => Exception e where #

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, Typeable)

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
    deriving Typeable

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
    deriving Typeable

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 (Typeable, 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

Minimal complete definition

Nothing

Instances

Exception Void 
Exception PatternMatchFail 
Exception RecSelError 
Exception RecConError 
Exception RecUpdError 
Exception NoMethodError 
Exception TypeError 
Exception NonTermination 
Exception NestedAtomically 
Exception BlockedIndefinitelyOnMVar 
Exception BlockedIndefinitelyOnSTM 
Exception Deadlock 
Exception AllocationLimitExceeded 
Exception AssertionFailed 
Exception SomeAsyncException 
Exception AsyncException 
Exception ArrayException 
Exception ExitCode 
Exception IOException 
Exception ErrorCall 
Exception ArithException 
Exception SomeException 
Exception UncatchableTCB # 
Exception InsufficientPrivs # 
Exception AnyLabelError # 
Label l => Exception (ResultExceedsLabel l) # 
Label l => Exception (LabelError l) # 

data SomeException :: * where #

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.

Constructors

SomeException :: SomeException 

throwLIO :: Exception e => e -> LIO l a Source #

Throw an exception.

catch :: (Label l, Exception e) => LIO l a -> (e -> LIO l a) -> LIO l a Source #

A simple wrapper around IO catch. The only subtlety is that code is not allowed to run unless the current label can flow to the current clearance. Hence, if the label exceeds the clearance, the exception is not caught. (Only a few conditions such as lWait or raising the clearance within scopeClearance can lead to the label exceeding the clarance, and an exception is always thrown at the time this happens.)

handle :: (Label l, Exception e) => (e -> LIO l a) -> LIO l a -> LIO l a Source #

A version of catch with the arguments swapped around.

try :: (Label l, Exception a1) => LIO l a -> LIO l (Either a1 a) Source #

Similar to catch, but returns an Either result which is (Right a) if no exception of type e was raised, or (Left ex) if an exception of type e was raised and its value is ex. If any other type of exception is raised than it will be propogated up to the next enclosing exception handler.

onException :: Label l => LIO l a -> LIO l b -> LIO l a Source #

Like finally, but only performs the final action if there was an exception raised by the computation.

finally :: Label l => LIO l a -> LIO l b -> LIO l a Source #

A variant of bracket where the return value from the first computation is not required.

bracket Source #

Arguments

:: Label l 
=> LIO l a

Computation to run first

-> (a -> LIO l c)

Computation to run last

-> (a -> LIO l b)

Computation to run in-between

-> LIO l b 

When you want to acquire a resource, do some work with it, and then release the resource, it is a good idea to use bracket, because bracket will install the necessary exception handler to release the resource in the event that an exception is raised during the computation. If an exception is raised, then bracket will re-raise the exception (after performing the release).

evaluate :: a -> LIO l a Source #

Forces its argument to be evaluated to weak head normal form when the resultant LIO action is executed.