tagged-exception-core (empty) → 2.0.0.0
raw patch · 10 files changed
+1615/−0 lines, 10 filesdep +basedep +exceptionsdep +extensible-exceptionssetup-changed
Dependencies added: base, exceptions, extensible-exceptions, mmorph, transformers
Files
- ChangeLog.md +16/−0
- LICENSE +30/−0
- Setup.hs +2/−0
- src/Control/Monad/TaggedException.hs +290/−0
- src/Control/Monad/TaggedException/Core.hs +446/−0
- src/Control/Monad/TaggedException/Hidden.hs +177/−0
- src/Control/Monad/TaggedException/Internal/Throws.hs +155/−0
- src/Control/Monad/TaggedException/Unsafe.hs +228/−0
- src/Control/Monad/TaggedException/Utilities.hs +187/−0
- tagged-exception-core.cabal +84/−0
+ ChangeLog.md view
@@ -0,0 +1,16 @@+# ChangeLog / ReleaseNotes++## Version 2.0.0.0++* Rewritten to use classes from [exceptions][] package.+* Uploaded to [Hackage][]:+ <http://hackage.haskell.org/package/tagged-exception-core-2.0.0.0>++++[exceptions]:+ http://hackage.haskell.org/package/exceptions+ "Extensible optionally-pure exceptions."+[Hackage]:+ http://hackage.haskell.org/+ "HackageDB (or just Hackage) is a collection of releases of Haskell packages."
+ LICENSE view
@@ -0,0 +1,30 @@+Copyright (c) 2009 - 2014, Peter Trsko++All rights reserved.++Redistribution and use in source and binary forms, with or without+modification, are permitted provided that the following conditions are met:++ * Redistributions of source code must retain the above copyright+ notice, this list of conditions and the following disclaimer.++ * Redistributions in binary form must reproduce the above+ copyright notice, this list of conditions and the following+ disclaimer in the documentation and/or other materials provided+ with the distribution.++ * Neither the name of Peter Trsko nor the names of other+ contributors may be used to endorse or promote products derived+ from this software without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR+A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT+OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,+SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT+LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ src/Control/Monad/TaggedException.hs view
@@ -0,0 +1,290 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE NoImplicitPrelude #-}+{-# OPTIONS_GHC -fno-warn-missing-import-lists #-}+-- |+-- Module: $HEADER$+-- Copyright: (c) 2009 - 2014 Peter Trsko+-- License: BSD3+--+-- Stability: provisional+-- Portability: non-portable (CPP, NoImplicitPrelude, depends on non-portable+-- modules)+module Control.Monad.TaggedException+ (+ -- * Introduction+ --+ -- | This library provides interface that is similar to base's /Extensible+ -- Exceptions/. It introduces 'Throws' monad transformer that uses phantom+ -- type to tag code that may raise exception. Intention is to make+ -- exceptions explicit and to enforce exception handling.+ --+ -- This approach is based on commonly used techniques:+ --+ -- * /Phantom Types/ <http://www.haskell.org/haskellwiki/Phantom_type>+ --+ -- * /Type Witnesses/ <http://www.haskell.org/haskellwiki/Type_witness>++ -- ** Why use this?+ --+ -- | Exceptions are one of the fastest and most scalable ways of handling+ -- failures and errors. One of the downsides of exceptions as defined in+ -- Haskell is that they aren't visible in type signatures as in example+ -- when using 'Data.Maybe.Maybe' or 'Control.Monad.Trans.Except.ExceptT'.+ --+ -- This library tries to get rid of this issue by making exceptions+ -- visible. On the other hand it makes things little more complicated, but+ -- fortunatelly not too much.+ --+ -- Some of the benefits of this approach are listed bellow.++ -- *** Unification of exception handling++ -- | Raising and handling exception becomes the same for all+ -- 'Control.Monad.Catch.MonadThrow' and 'Control.Monad.Catch.MonadCatch'+ -- instances. This includes code that uses exceptions in @IO@ monad and+ -- @ErrorT@ style error handling. All that can be easily modified to use+ -- API defined by this library.+ --+ -- For ilustration there is a great summary of various ways of error+ -- handling in Haskell:+ --+ -- * <http://blog.ezyang.com/2011/08/8-ways-to-report-errors-in-haskell-revisited/ 8 ways to report errors in Haskell revisited>+ --+ -- * <http://www.randomhacks.net/articles/2007/03/10/haskell-8-ways-to-report-errors/ 8 ways to report errors in Haskell>+ --+ -- Posts mentioned above show that any unification or framework for+ -- transforming one error handling technique to another are very benefitial+ -- in practice.++ -- *** Avoiding fail+ --+ -- | Sometimes @'Monad'('fail')@ is used to generalize exception handling.+ -- While it provides a generalized interface it also introduces controversy+ -- that sorrounds 'fail'.+ --+ -- This library allows usege of similar approach without using 'fail' and+ -- with explicitly visible exception.+ --+ -- Instead of function like:+ --+ -- > lookup+ -- > :: Monad m+ -- > => Container Key Value+ -- > -> Key+ -- > -> m Value+ --+ -- this library allows to write:+ --+ -- > lookup+ -- > :: MonadThrow m+ -- > => Container Key Value+ -- > -> Key+ -- > -> Throw LookupFailure m Value+ --+ -- where @LookupFailure@ is instance of 'Control.Exception.Exception'+ -- class. While in some ways it's similar to using+ -- 'Control.Monad.Trans.Except.ExceptT', it has all the flexibility of+ -- /extensible-exceptions/ for arbitrary 'Control.Monad.Catch.MonadThrow'+ -- instance.++ -- ** Dependencies+ --+ -- | This package is trying to keep dependencies at minimum. Here is list+ -- of current dependencies:+ --+ -- * /base/+ --+ -- * /exceptions/: Provides 'Control.Monad.Catch.MonadThrow',+ -- 'Control.Monad.Catch.MonadCatch' and 'Control.Monad.Catch.MonadMask'+ -- type classes.+ --+ -- * /extensible-exceptions/ for /4 >= base < 4.2/+ --+ -- * /transformers >= 0.2 && < 0.4/: De facto current standard for monad+ -- transformers. Included in newer versions of HaskellPlatform.+ --+ -- * /mmorph/ >= 1.0.0 && < 1.1: Monad morphism utilities. Currently not+ -- in HaskellPlatform.++ -- ** Naming conventions+ --+ -- | Names of basic functions are the same as those in "Control.Exception"+ -- module, but differ in it's type signature. They operate on tagged code+ -- and are therefore limited to operate only on exceptions specified by the+ -- phantom type.+ --+ -- Exception, to above rule, is 'throw' function which does not throw+ -- exception from pure code, as does 'Control.Exception.throw', but from+ -- monadic code. So, it is more equivalent to 'Control.Exception.throwIO'.++ -- *** \<function\> vs. \<function\>'+ --+ -- | Functions with prime at the end of there name aren't restricted by the+ -- phantom type while those without it are. Functions with prime can+ -- therefore operate on arbitrary exceptions. Use such functions when+ -- operating on exceptions that are different from exception specified by a+ -- phantom type, i.e. hidden ones.+ --+ -- In case of 'System.IO.IO' monad, primed functions behave as those from+ -- "Control.Exception" module with the same name, but without prime of+ -- course.++ -- *** lift\<n\>T vs. liftT\<n\>+ --+ -- | The @lift\<n\>T@ are basicaly saying lift \<n\> times (e.g. @'lift2T'+ -- = 'liftT' . 'liftT'@) while @liftT\<n\>@ says lift one time but operate+ -- on function with arity \<n\>. This was choosen to be consistent with+ -- @liftM@, @liftM2@, @liftA@, @liftA2@, etc.++ -- * Usage+ -- $usage++ -- ** Importing+ --+ -- | When using older /base/ library function 'catch' clashes with+ -- @Prelude(catch)@, so either import with hidden @Prelude(catch)@:+ --+ -- > import Prelude hiding (catch)+ -- > import Control.Monad.TaggedException+ --+ -- or use import like:+ --+ -- > import Control.Monad.TaggedException as E+ --+ -- and then use @E.catch@, in later case you can also use qualified import:+ --+ -- > import qualified Control.Monad.TaggedException as E+ --+ -- It is recomended to use explicit import list or, as mentioned before,+ -- qualified import. See also /Import modules properly/ on /Haskell Wiki/:+ -- <http://www.haskell.org/haskellwiki/Import_modules_properly>.+ --+ -- Classes 'Control.Monad.Catch.MonadCatch',+ -- 'Control.Monad.Catch.MonadThrow' and 'Control.Monad.Catch.MonadMask'+ -- aren't reexported. To use them in your type signatures you'll need to+ -- import them from /exceptions/ package:+ --+ -- > import Control.Monad.Catch (MonadCatch, MonadMask, MonadThrow)+ --+ -- Same goes for 'Exception' class which is provided by /base/ (or by+ -- /extensible-exceptions/ for older bases):+ --+ -- > import Control.Exception (Exception)++ -- * API documentation++ -- ** Library core+ --+ -- | Basic library interface. Main idea behind it is to provide very+ -- stable API that can be imported directly from+ -- "Control.Monad.TaggedException.Core" module or as part of this one.+ --+ -- Among others it provides:+ --+ -- * 'Throws' newtype that is used for tagging monadic code with exception+ -- type.+ --+ -- * A lot of combinators for tagged monadic code. In example \"@'liftT' ::+ -- ('Exception' e, 'MonadThrow' m) => m a -> 'Throws' e m a@\" lifts+ -- monadic code in to tagged monadic code.+ --+ -- * Functions defined on top of 'Control.Monad.Catch.MonadThrow' and+ -- 'MonadCatch', like 'throw', 'catch' and 'handle'.+ module Control.Monad.TaggedException.Core++ -- ** Hidden exceptions+ --+ -- | Support for hidden/uncaught exceptions. The ideas behind hiding+ -- thrown exception is:+ --+ -- 1. Be compatible with /extensible-exceptions/ ("Control.Exception"),+ -- in sense that all current @IO@ code doesn't reflect raised+ -- exceptions in it's type. All standard exceptions, exported by+ -- "Control.Exception" module, are instances of 'HiddenException'.+ --+ -- 2. Programs, and their code, are multilayered things. Sometimes+ -- exceptions aren't ment to be caught in certain layers. See also+ -- <http://www.haskell.org/haskellwiki/Error_vs._Exception Error vs. Exception>+ -- on /Haskell Wiki/.+ --+ -- See "Control.Monad.TaggedException.Hidden" for examples.+ , module Control.Monad.TaggedException.Hidden++ -- ** Asynchronous exceptions and bracket family of functions+ , module Control.Monad.TaggedException.Utilities++ -- * Some related work+ --+ -- | There is already more then one package that introduces similar+ -- interfaces and also many others that are dealing with the same problem+ -- domain. Just to list some:+ --+ -- * <http://hackage.haskell.org/package/control-monad-attempt control-monad-attempt>+ --+ -- * <http://hackage.haskell.org/package/control-monad-exception control-monad-exception>:+ -- Exception monad transformer with explicitly typed exceptions.+ --+ -- * <http://hackage.haskell.org/package/explicit-exception explicit-exception>:+ -- Synchronous and Asynchronous exceptions which are explicit in the type+ -- signature.+ --+ -- * <http://hackage.haskell.org/package/failure failure> with instances+ -- for <http://hackage.haskell.org/package/transformers transformers>+ -- defined in+ -- <http://hackage.haskell.org/package/control-monad-failure control-monad-failure>.+ --+ -- * <http://hackage.haskell.org/package/MonadCatchIO-mtl MonadCatchIO-mtl>+ -- and+ -- <http://hackage.haskell.org/package/MonadCatchIO-transformers MonadCatchIO-transformers>:+ -- This libraries export @class MonadIO m => MonadCatchIO m@ that catches+ -- lifting neccessary for exception handling in encapsulated+ -- 'System.IO.IO' monad.+ --+ -- * <http://hackage.haskell.org/package/monad-control monad-control>:+ -- Based on /monad-peel/.+ --+ -- * <http://hackage.haskell.org/package/monad-peel monad-peel>++ )+ where++import Control.Monad.TaggedException.Core+import Control.Monad.TaggedException.Hidden+import Control.Monad.TaggedException.Utilities++-- $usage+--+-- Example of reflecting reised exception in type:+--+-- > {-# LANGUAGE DeriveDataTypeable #-}+-- >+-- > import Control.Exception (Exception)+-- >+-- > import Control.Monad.TaggedException (Throws)+-- > import qualified Control.Monad.TaggedException as E (liftT, throw)+-- > import Data.Typeable (Typeable)+-- >+-- >+-- > data NotReady = NotReady String+-- > deriving (Show, Typeable)+-- > -- Both required by Exception class+-- >+-- > instance Exception NotReady+-- >+-- > myFunction :: Input -> Throws NotReady IO Output+-- > myFunction input = do+-- >+-- > ... some stuff ...+-- >+-- > -- isReady :: Input -> IO Bool+-- > ready <- E.liftT $ isReady input+-- > unless ready+-- > . E.throw $ NotReady "Resource of myFunction is not ready."+-- >+-- > ... some other stuff ...+--+-- Caller of this function is forced to catch/handle this exception or reflect+-- it in it's type too.+--+-- See "Control.Monad.TaggedException.Core" and+-- "Control.Monad.TaggedException.Hidden" for more examples.
+ src/Control/Monad/TaggedException/Core.hs view
@@ -0,0 +1,446 @@+{-# LANGUAGE NoImplicitPrelude #-}+-- |+-- Module: $HEADER$+-- Description: Core functionality.+-- Copyright: (c) 2009 - 2014 Peter Trsko.+-- License: BSD3+--+-- Stability: provisional+-- Portability: non-portable (NoImplicitPrelude, depends on non-portable+-- modules)+--+-- Core functionality.+module Control.Monad.TaggedException.Core+ (+ -- * MonadException+ throw+ , catch+ , catch'+ , handle+ , handle'+ , try+ , mapException+ , onException+ , onException'++ -- * Exception tag+ , Throws++ -- ** Cobinators+ , liftT+ , lift2T+ , lift3T+ , liftT1+ , liftT2+ , liftT3+ , joinT+ , joinT3+ , flipT+ , insideT+ , insideT2+ , insideT3+ , insideTf+ , insideTf2+ , embedT+ )+ where++import Control.Exception (Exception)+import Data.Either (Either)+import Data.Function ((.), flip)+import Data.Functor (Functor)++import Control.Monad.Catch (MonadCatch, MonadThrow)+import qualified Control.Monad.Catch as Exceptions++import Control.Monad.TaggedException.Internal.Throws (Throws(Throws))+import qualified Control.Monad.TaggedException.Unsafe as Unsafe+ ( embedT+ , flipT+ , insideT+ , insideT2+ , insideT3+ , insideTf+ , insideTf2+ , joinT+ , joinT3+ , liftT1+ , liftT2+ , liftT3+ , throwsOne+ , throwsThree+ , throwsTwo+ )+++-- | Throw an exception. To raise an \"inner\" exception following can be+-- used:+--+-- @+-- 'liftT' . 'throw'+-- :: ('MonadCatch' m, 'Exception' e, 'Exception' e')+-- => e+-- -> 'Throws' e' ('Throws' e m) a+-- @+throw :: (Exception e, MonadThrow m) => e -> Throws e m a+throw = Throws . Exceptions.throwM++-- | Catch exception.+--+-- To catch inner exception following construct can be used:+--+-- @+-- 'catch' . 'flipT'+-- :: ('Exception' e, 'Exception' e', 'MonadCatch' m)+-- => 'Throws' e' ('Throws' e m) a+-- -> (e -> 'Throws' e' m a)+-- -> 'Throws' e' m a+-- @+catch :: (Exception e, MonadCatch m) => Throws e m a -> (e -> m a) -> m a+catch (Throws ma) = Exceptions.catch ma++-- | Catch any exception.+catch' :: (Exception e, MonadCatch m) => m a -> (e -> m a) -> m a+catch' = Exceptions.catch++-- | Flipped version of 'catch'. Usage example:+--+-- @+-- foo = 'handle' exceptionHandler $ do+-- ...+-- where exceptionHandler = ...+-- @+--+-- Handle \"inner\" exception:+--+-- @+-- 'insideT' . 'handle'+-- :: ('MonadCatch' m, 'Exception' e, 'Exception' e')+-- => (e' -> m a)+-- -> 'Throws' e ('Throws' e' m) a+-- -> 'Throws' e m a+-- @+handle+ :: (Exception e, MonadCatch m)+ => (e -> m a)+ -> Throws e m a+ -> m a+handle = flip catch+{-# INLINE handle #-}++-- | Flipped version of 'catch''+handle'+ :: (Exception e, MonadCatch m)+ => (e -> m a)+ -> m a+ -> m a+handle' = flip catch'+{-# INLINE handle' #-}++-- | Similar to 'catch', but returns 'Either' exception or result.+--+-- Inner try:+--+-- @+-- 'try' . 'flipT'+-- :: ('Exception' e, 'Exception' e', MonadCatch m)+-- => 'Throws' e' ('Throws' e m) a+-- -> 'Throws' e' m ('Either' e a)+-- @+try+ :: (Exception e, MonadCatch m)+ => Throws e m a+ -> m (Either e a)+try (Throws ma) = Exceptions.try ma++-- | Map one exception to another.+--+-- Mapping \"inner\" exception has generally two forms:+--+-- 1\. Modifying raised exception, but not changing its type:+--+-- @+-- 'liftT1' . 'mapException'+-- :: ('Exception' e, 'Exception' e', 'MonadCatch' m)+-- => (e -> e)+-- -> 'Throws' e' ('Throws' e m) a+-- -> 'Throws' e' ('Throws' e m) a+-- @+--+-- 2\. Modifying raised exception, including its type:+--+-- @+-- 'insideT' . 'mapException'+-- :: ('Exception' e, 'Exception' e1, 'Exception' e2, 'MonadCatch' m)+-- => (e1 -> e2)+-- -> 'Throws' e ('Throws' e1 m) a+-- -> 'Throws' e ('Throws' e2 m) a+-- @+--+-- Unhiding exception by mapping it in to a different type of exception:+--+-- @+-- \\f -> 'mapException' f . 'liftT'+-- :: ('Exception' e, 'Exception' e', 'MonadCatch' m)+-- => (e -> e')+-- -> m a+-- -> 'Throws' e' m a+-- @+mapException+ :: (Exception e, Exception e', MonadCatch m)+ => (e -> e')+ -> Throws e m a+ -> Throws e' m a+mapException = flip (catch . flipT . liftT) . (throw .)++-- | Run computation if exception was raised. Basically:+--+-- @+-- m ``onException`` n = 'liftT' m ``catch`` \\e -> 'liftT' n >> 'throw' e+-- @+onException+ :: (Exception e, MonadCatch m)+ => Throws e m a+ -- ^ Computation that may raise exception+ -> m b+ -- ^ The computation to run if an exception @e@ is raised+ -> Throws e m a+onException (Throws ma) = Throws . Exceptions.onException ma++-- | Same as 'onException', but uses 'catch'' and so second computation is+-- executed if any exception is raised.+onException'+ :: (MonadCatch m)+ => m a+ -- ^ Computation that may raise exception+ -> m b+ -- ^ The computation to run if an exception is raised+ -> m a+onException' = Exceptions.onException++-- {{{ Exception tag -- Combinators -------------------------------------------++-- | Construct exception tag, with type restrictions.+--+-- Reflect raised exception in function's type:+--+-- > import Control.Monad.TaggedException (Throws, liftT)+-- > import System.IO (Handle, IOMode)+-- > import qualified System.IO as IO (openFile)+-- >+-- >+-- > openFile :: FilePath -> IOMode -> Throws IOError IO Handle+-- > openFile = (liftT .) . IO.openFile+--+-- Lifting @m@ to @'Throws' e m@:+--+-- > import Control.Exception (Exception)+-- >+-- > import Control.Monad.TaggedException (Throws, liftT, throw)+-- > import Data.Typeable (Typeable)+-- >+-- >+-- > data EmptyString = EmptyString+-- > deriving (Show, Typeable)+-- >+-- > instance Exception EmptyString+-- >+-- > writeIfNotEmpty+-- > :: FilePath+-- > -> String+-- > -> Throws EmptyString IO ()+-- > writeIfNotEmpty filename str = do+-- > when (null str) $ throw EmptyString+-- > liftT $ writeFile filename str+--+-- We have a some commonly used patterns:+--+-- @+-- ('liftT' .)+-- :: ('Exception' e, 'MonadThrow' m)+-- => (a -> m b)+-- -> a -> 'Throws' e m b+-- @+--+-- Above is also usable for lifting throw-like functions:+--+-- @+-- import Control.Monad.Trans.Class (MonadTrans(lift))+--+-- (('liftT' . 'Control.Monad.Trans.Class.lift') .)+-- :: ( 'Exception' e+-- , 'MonadThrow' m+-- , 'MonadThrow' (t m)+-- , 'Control.Monad.Trans.Class.MonadTrans' t)+-- => (a -> m b)+-- -> a -> 'Throws' e (t m) b+-- @+liftT :: (Exception e, MonadThrow m) => m a -> Throws e m a+liftT = Unsafe.throwsOne+{-# INLINE liftT #-}++-- | Shorthand for @'liftT' . 'liftT'@.+lift2T+ :: (Exception e, Exception e', MonadThrow m)+ => m a+ -> Throws e' (Throws e m) a+lift2T = Unsafe.throwsTwo+{-# INLINE lift2T #-}++-- | Shorthand for @'liftT' . 'liftT' . 'liftT'@.+lift3T+ :: (Exception e, Exception e', Exception e'', MonadThrow m)+ => m a+ -> Throws e'' (Throws e' (Throws e m)) a+lift3T = Unsafe.throwsThree+{-# INLINE lift3T #-}++-- | 'liftT' for functions with arity one.+liftT1+ :: (Exception e, MonadThrow m)+ => (m a -> m b)+ -> Throws e m a -> Throws e m b+liftT1 = Unsafe.liftT1+{-# INLINE liftT1 #-}++-- | 'liftT' for functions with arity two.+liftT2+ :: (Exception e, MonadThrow m)+ => (m a -> m b -> m c)+ -> Throws e m a -> Throws e m b -> Throws e m c+liftT2 = Unsafe.liftT2+{-# INLINE liftT2 #-}++-- | 'liftT' for functions with arity three.+liftT3+ :: (Exception e, MonadThrow m)+ => (m a -> m b -> m c -> m d)+ -> Throws e m a -> Throws e m b -> Throws e m c -> Throws e m d+liftT3 = Unsafe.liftT3+{-# INLINE liftT3 #-}++-- | Join two outermost exception tags.+joinT+ :: (Exception e, MonadThrow m)+ => Throws e (Throws e m) a+ -> Throws e m a+joinT = Unsafe.joinT+{-# INLINE joinT #-}++-- | Join three outermost exception tags.+joinT3+ :: (Exception e, MonadThrow m)+ => Throws e (Throws e (Throws e m)) a+ -> Throws e m a+joinT3 = Unsafe.joinT3+{-# INLINE joinT3 #-}++-- | Flip two outermost exception tags.+flipT+ :: (Exception e, Exception e', MonadThrow m)+ => Throws e' (Throws e m) a+ -> Throws e (Throws e' m) a+flipT = Unsafe.flipT+{-# INLINE flipT #-}++-- | Generalized 'liftT'. Usage examples:+--+-- @+-- 'insideT' lift+-- :: ('MonadThrow' (t m), 'MonadThrow' m, 'Exception' e, MonadTrans t)+-- => 'Throws' e m b+-- -> 'Throws' e (t m) b+-- @+--+-- This is variation on the first example that explicitly lifts monad:+--+-- 'insideT' WriterT+-- :: ('Exception' e, 'MonadThrow' m, Monoid w)+-- => 'Throws' e m (b, w)+-- -> 'Throws' e (WriterT w m) b+--+-- Some useful compositions of exception tag combinators:+--+-- @+-- 'insideT' 'flipT'+-- :: ('Exception' e0, 'Exception' e1, 'Exception' e2, 'MonadThrow' m)+-- => 'Throws' e0 ('Throws' e1 ('Throws' e2 m)) a+-- -> 'Throws' e0 ('Throws' e2 ('Throws' e1 m)) a+-- @+--+-- @+-- 'flipT' . 'insideT' 'flipT'+-- :: ('Exception' e0, 'Exception' e1, 'Exception' e2, 'MonadThrow' m)+-- => 'Throws' e0 ('Throws' e1 ('Throws' e2 m)) a+-- -> 'Throws' e2 ('Throws' e0 ('Throws' e1 m)) a+-- @+insideT+ :: (Exception e, MonadThrow m, MonadThrow m')+ => (m a -> m' b)+ -> Throws e m a -> Throws e m' b+insideT = Unsafe.insideT+{-# INLINE insideT #-}++-- | Variant of 'insideT'.+--+-- Usage example:+--+-- @+-- 'insideTf' StateT+-- :: ('Exception' e, 'MonadThrow' m)+-- => (s -> 'Throws' e m (a, s))+-- -> 'Throws' e (StateT s m) a+-- @+insideTf+ :: (Exception e, Functor f, MonadThrow m, MonadThrow m')+ => (f (m a) -> m' b)+ -> f (Throws e m a)+ -> Throws e m' b+insideTf = Unsafe.insideTf+{-# INLINE insideTf #-}++-- | Variant of 'insideT'.+--+-- Usage example:+--+-- @+-- 'insideTf2' RWST+-- :: ('Exception' e, 'MonadThrow' m)+-- => (r -> s -> 'Throws' e m (a, s, w))+-- -> 'Throws' e (RWST r w s m) a+-- @+insideTf2+ :: (Exception e, Functor f, Functor f', MonadThrow m, MonadThrow m')+ => (f (f' (m a)) -> m' b)+ -> f (f' (Throws e m a))+ -> Throws e m' b+insideTf2 = Unsafe.insideTf2+{-# INLINE insideTf2 #-}++-- | Generalized 'liftT2'.+insideT2+ :: (Exception e, MonadThrow m1, MonadThrow m2, MonadThrow m3)+ => (m1 a -> m2 b -> m3 c)+ -> Throws e m1 a -> Throws e m2 b -> Throws e m3 c+insideT2 = Unsafe.insideT2+{-# INLINE insideT2 #-}++-- | Generalized 'liftT3'.+insideT3+ :: (Exception e, MonadThrow m1, MonadThrow m2, MonadThrow m3,+ MonadThrow m4)+ => (m1 a -> m2 b -> m3 c -> m4 d)+ -> Throws e m1 a -> Throws e m2 b -> Throws e m3 c -> Throws e m4 d+insideT3 = Unsafe.insideT3+{-# INLINE insideT3 #-}++-- |+--+-- Since @1.2.0.0@+embedT :: (Exception e, MonadThrow m, MonadThrow m')+ => (m a -> Throws e m' b)+ -> Throws e m a -> Throws e m' b+embedT = Unsafe.embedT+{-# INLINE embedT #-}++-- }}} Exception tag -- Combinators -------------------------------------------
+ src/Control/Monad/TaggedException/Hidden.hs view
@@ -0,0 +1,177 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE NoImplicitPrelude #-}+-- |+-- Module: $HEADER$+-- Description: Support for hidden exceptions.+-- Copyright: (c) 2009 - 2014 Peter Trsko+-- License: BSD3+--+-- Stability: provisional+-- Portability: non-portable (CPP, NoImplicitPrelude, depends on non-portable+-- module)+module Control.Monad.TaggedException.Hidden+ (+ -- * HiddenException class+ --+ -- | Since 'HiddenException' provides default implementation for 'hide'+ -- method making instances of it is trivial. Example of how to create+ -- instance of HiddenException:+ --+ -- > data MyException = MyException String+ -- > deriving (Typeable)+ -- >+ -- > instance Show MyException where+ -- > showsPrec _ (MyException msg) =+ -- > showString "MyException: " . shows msg+ -- >+ -- > instance Exception MyException+ -- > instance HiddenException MyException+ HiddenException(..)++ -- ** Mapping existing visible exception to hidden ones+ --+ -- | This is a prefered way of hiding exceptions. Difference from just+ -- hiding the type tag and mapping it in to hidden exception is that in+ -- later case we can provide additional information. Most important is to+ -- specify why that particluar exception was hidden.+ --+ -- Example:+ --+ -- > data UnrecoverableException+ -- > = UnrecoverableIOException String IOException+ -- > deriving (Typeable)+ -- >+ -- > instance Show UnrecoverableException where+ -- > showsPrec _ (UnrecoverableIOException info e)+ -- > showString "Unrecoverable exception occurred in "+ -- > . showString info . showString ": " . shows e+ -- >+ -- > instance Exception UnrecoverableException+ -- > instance HiddenException UnrecoverableException+ -- >+ -- > hideIOException+ -- > :: (MonadCatch e)+ -- > => String+ -- > -> Throws IOException m a+ -- > -> m a+ -- > hideIOException = hideWith . UnrecoverableIOException+ , hideWith++ -- ** Raising hidden exceptions+ , throwHidden+ , throw'+ )+ where++import Control.Exception (Exception)+import qualified Control.Exception as E+ ( ArithException+ , ArrayException+ , AssertionFailed+ , AsyncException+#if MIN_VERSION_base(4,2,0)+ , BlockedIndefinitelyOnMVar+ , BlockedIndefinitelyOnSTM+#else+ , BlockedIndefinitely+ , BlockedOnDeadMVar+#endif+ , Deadlock+ , ErrorCall+ , IOException+ , NestedAtomically+ , NoMethodError+ , NonTermination+ , PatternMatchFail+ , RecConError+ , RecSelError+ , RecUpdError+#if MIN_VERSION_base(4,7,0)+ , SomeAsyncException+#endif+ , SomeException+ )+import Data.Dynamic (Dynamic)+import Data.Function ((.))+import System.Exit (ExitCode)++import Control.Monad.Catch (MonadCatch, MonadThrow)+import qualified Control.Monad.Catch as Exceptions+ ( MonadCatch(catch)+ , MonadThrow(throwM)+ )++-- This module depends only on internals and nothing else from this package.+-- Try, hard, to keep it that way.+import Control.Monad.TaggedException.Internal.Throws (Throws(Throws))+import qualified Control.Monad.TaggedException.Internal.Throws as Internal+ (Throws(hideException))+++-- | Class for exception that can be removed from the type signature. Default+-- implementation for 'hideException' method is provided.+class Exception e => HiddenException e where+ -- | Hide exception tag.+ hideException :: MonadThrow m => Throws e m a -> m a+ hideException = Internal.hideException+ {-# INLINE hideException #-}++-- {{{ HiddenException -- Instances -------------------------------------------+-- (sorted alphabetically)++instance HiddenException Dynamic+instance HiddenException E.ArithException+instance HiddenException E.ArrayException+instance HiddenException E.AssertionFailed+instance HiddenException E.AsyncException+#if MIN_VERSION_base(4,2,0)+instance HiddenException E.BlockedIndefinitelyOnMVar+instance HiddenException E.BlockedIndefinitelyOnSTM+#else+instance HiddenException E.BlockedIndefinitely+instance HiddenException E.BlockedOnDeadMVar+#endif+instance HiddenException E.Deadlock+instance HiddenException E.ErrorCall+instance HiddenException E.IOException+instance HiddenException E.NestedAtomically+instance HiddenException E.NoMethodError+instance HiddenException E.NonTermination+instance HiddenException E.PatternMatchFail+instance HiddenException E.RecConError+instance HiddenException E.RecSelError+instance HiddenException E.RecUpdError+#if MIN_VERSION_base(4,7,0)+instance HiddenException E.SomeAsyncException+#endif+instance HiddenException E.SomeException+instance HiddenException ExitCode++-- }}} HiddenException -- Instances -------------------------------------------++-- | Map exception before hiding it.+--+-- This is the preferred way to do exception hiding, by mapping it in to a+-- different exception that better describes its fatality.+hideWith+ :: (Exception e, HiddenException e', MonadCatch m)+ => (e -> e')+ -> Throws e m a+ -> m a+hideWith f (Throws ma) = Exceptions.catch ma (Exceptions.throwM . f)++-- | Throw exceptions and then disregard type tag.+throwHidden+ :: (HiddenException e, MonadThrow m)+ => e+ -> m a+throwHidden = Exceptions.throwM+{-# INLINE throwHidden #-}++-- | Alias for @throwHidden@.+throw'+ :: (HiddenException e, MonadThrow m)+ => e+ -> m a+throw' = Exceptions.throwM+{-# INLINE throw' #-}
+ src/Control/Monad/TaggedException/Internal/Throws.hs view
@@ -0,0 +1,155 @@+{-# LANGUAGE CPP #-}+{-# LANGUAGE NoImplicitPrelude #-}+{-# LANGUAGE PolyKinds #-}+{-# LANGUAGE RankNTypes #-}+#ifdef KIND_POLYMORPHIC_TYPEABLE+{-# LANGUAGE DeriveDataTypeable #-}+#endif+{-# LANGUAGE DeriveGeneric #-}+-- |+-- Module: $HEADER$+-- Description: Data type for associating monadic value with phantom type.+-- Copyright: (c) 2009 - 2014 Peter Trsko+-- License: BSD3+--+-- Maintainer: peter.trsko@gmail.com+-- Stability: stable+-- Portability: non-portable (CPP, NoImplicitPrelude, PolyKinds, RankNTypes+-- DeriveDataTypeable, DeriveGeneric)+--+-- Data type for associating monadic value with phantom type. In case of this+-- library it will always be associated with a type of exception it may throw.+module Control.Monad.TaggedException.Internal.Throws+ (+ Throws(..)+ , liftMask+ )+ where++import Control.Applicative+ ( Alternative((<|>), empty, many, some)+ , Applicative((<*), (<*>), (*>), pure)+ )+import Control.Monad+ ( Monad((>>), (>>=), fail, return)+ , MonadPlus(mplus, mzero)+ )+import Data.Functor (Functor(fmap))+import Data.Function ((.))+#ifdef KIND_POLYMORPHIC_TYPEABLE+import Data.Typeable (Typeable)+#endif+import GHC.Generics (Generic)++import Control.Monad.IO.Class (MonadIO(liftIO))+import Control.Monad.Trans.Class (MonadTrans(lift))++import Control.Monad.Catch+ ( MonadCatch(catch)+ , MonadMask(mask, uninterruptibleMask)+ , MonadThrow(throwM)+ )+import Control.Monad.Morph (MFunctor(hoist), MMonad(embed))+++-- | Exception tag.+newtype Throws e m a = Throws+ { hideException :: m a+ -- ^ Hide one exception.+ }+ deriving+ ( Generic+#ifdef KIND_POLYMORPHIC_TYPEABLE+ , Typeable+#endif+ )++-- | Lift @mask@ operation in to 'Throws' context.+liftMask+ :: (((forall a. m a -> m a) -> m b) -> m b)+ -> ((forall a. Throws e m a -> Throws e m a) -> Throws e m b)+ -> Throws e m b+liftMask msk f = Throws (msk (\restore -> hideException (f (liftT restore))))+ where+ liftT :: (m a -> m a) -> (Throws e m a -> Throws e m a)+ liftT g (Throws m) = Throws (g m)+{-# INLINABLE liftMask #-}++-- {{{ Instances --------------------------------------------------------------++instance Functor f => Functor (Throws e f) where+ -- (a -> b) -> Throws e f a -> Throws e f b+ fmap f (Throws ma) = Throws (fmap f ma)++instance Applicative f => Applicative (Throws e f) where+ pure = Throws . pure+ Throws x <*> Throws y = Throws (x <*> y)+ Throws x *> Throws y = Throws (x *> y)+ Throws x <* Throws y = Throws (x <* y)++instance Alternative f => Alternative (Throws e f) where+ empty = Throws empty+ Throws x <|> Throws y = Throws (x <|> y)+ some (Throws ma) = Throws (some ma)+ many (Throws ma) = Throws (many ma)++instance Monad m => Monad (Throws e m) where+ return = Throws . return+ Throws ma >>= f = Throws (ma >>= hideException . f)+ Throws ma >> Throws na = Throws (ma >> na)+ fail = Throws . fail++instance MonadPlus m => MonadPlus (Throws e m) where+ mzero = Throws mzero+ Throws m `mplus` Throws n = Throws (m `mplus` n)++-- {{{ Instances: transformers ------------------------------------------------++instance MonadIO m => MonadIO (Throws e m) where+ liftIO = Throws . liftIO++instance MonadTrans (Throws e) where+ lift = Throws++-- }}} Instances: transformers ------------------------------------------------++-- {{{ Instances: mmorph ------------------------------------------------------++-- | Since @1.2.0.0@.+instance MFunctor (Throws e) where+ -- :: Monad m => (forall a. m a -> n a) -> Throws e m b -> Throws e n b+ hoist f x = Throws (f (hideException x))++-- | Since @1.2.0.0@.+instance MMonad (Throws e) where+ -- :: Monad n+ -- => (forall a. m a -> Throws e n a)+ -- -> Throws e m b -> Throws e n b+ embed f x = f (hideException x)++-- }}} Instances: mmorph ------------------------------------------------------++-- {{{ Instances: exceptions --------------------------------------------------++-- | Since @2.0.0.0@.+instance MonadThrow m => MonadThrow (Throws e m) where+ -- throwM :: Exception e' => e' -> Throws m a+ throwM = Throws . throwM++-- | Since @2.0.0.0@.+instance MonadCatch m => MonadCatch (Throws e m) where+ -- :: Exception e' => Throws m a -> (e' -> Throws m a) -> Throws m a+ catch (Throws ma) f = Throws (catch ma (hideException . f))++-- | Since @2.0.0.0@.+instance MonadMask m => MonadMask (Throws e m) where+ -- :: ((forall a. Throws e m a -> Throws e m a) -> Throws e m b)+ -- -> Throws e m b+ mask = liftMask mask++ -- :: ((forall a. Throws e m a -> Throws e m a) -> Throws e m b)+ -- -> Throws e m b+ uninterruptibleMask = liftMask uninterruptibleMask++-- }}} Instances: exceptions --------------------------------------------------+-- }}} Instances --------------------------------------------------------------
+ src/Control/Monad/TaggedException/Unsafe.hs view
@@ -0,0 +1,228 @@+{-# LANGUAGE NoImplicitPrelude #-}+-- |+-- Module: $HEADER$+-- Description: Unsafe exception tag cobinators and specific lifting+-- functions.+-- Copyright: (c) 2009 - 2014 Peter Trsko+-- License: BSD3+--+-- Stability: provisional+-- Portability: non-portable (NoImplicitPrelude)+--+-- Unsafe exception tag cobinators and specific lifting functions. Import this+-- module if creating new 'MonadException' instance(s) that can not be created+-- otherwise.+--+-- Preferably import as:+--+-- > import qualified Control.Monad.TaggedException.Unsafe as Unsafe+module Control.Monad.TaggedException.Unsafe+ ( Throws+ , throwsOne+ , throwsTwo+ , throwsThree+ , hideOne+ , hideTwo+ , hideThree++ , liftT1+ , liftT2+ , liftT3+ , insideT+ , insideTf+ , insideTf2+ , insideT2+ , insideT3+ , joinT+ , joinT3+ , flipT+ , embedT++ , liftMask+ , liftBindLike+ , liftFlipBindLike+ , liftKleisliLike+ )+ where++import Data.Function ((.), ($))+import Data.Functor (Functor(fmap))++import Control.Monad.TaggedException.Internal.Throws+ ( Throws(Throws, hideException)+ , liftMask+ )+++-- | Construct exception tag, but without 'Control.Monad.Catch.MonadThrow'+-- restriction.+throwsOne :: m a -> Throws e m a+throwsOne = Throws++-- | Shorthand for @'throwsOne' . 'throwsOne'@.+throwsTwo :: m a -> Throws e' (Throws e m) a+throwsTwo = Throws . Throws++-- | Shorthand for @'throwsOne' . 'throwsOne' . 'throwsOne'@.+throwsThree :: m a -> Throws e'' (Throws e' (Throws e m)) a+throwsThree = Throws . Throws . Throws++-- | Hide one exceptions, but without 'Control.Monad.Catch.MonadThrow'+-- restriction.+hideOne :: Throws e m a -> m a+hideOne = hideException++-- | Hide two exceptions, but without 'Control.Monad.Catch.MonadThrow'+-- restriction.+hideTwo :: Throws e (Throws e' m) a -> m a+hideTwo = hideException . hideException++-- | Hide three exceptions, but without 'Control.Monad.Catch.MonadThrow'+-- restriction.+hideThree :: Throws e (Throws e' (Throws e'' m)) a -> m a+hideThree = hideException . hideException . hideException++-- | 'liftT' for functions with arity one. Isn't restricted just to+-- 'Control.Monad.Catch.MonadThrow' instances.+liftT1+ :: (m a -> m b)+ -> Throws e m a -> Throws e m b+liftT1 = (Throws .) . (. hideException)++-- | 'liftT' for functions with arity two. Isn't restricted just to+-- 'Control.Monad.Catch.MonadThrow' instances.+liftT2+ :: (m a -> m b -> m c)+ -> Throws e m a -> Throws e m b -> Throws e m c+liftT2 f m n = Throws $ f (hideException m) (hideException n)++-- | 'liftT' for functions with arity three. Isn't restricted just to+-- 'Control.Monad.Catch.MonadThrow' instances.+liftT3+ :: (m a -> m b -> m c -> m d)+ -> Throws e m a -> Throws e m b -> Throws e m c -> Throws e m d+liftT3 f m n o =+ Throws $ f (hideException m) (hideException n) (hideException o)++-- | Generalized 'liftT'.+insideT+ :: (m a -> m' b)+ -> Throws e m a -> Throws e m' b+insideT = (Throws .) . (. hideException)++-- | Variant 'insideT'.+insideTf+ :: (Functor f)+ => (f (m a) -> m' b)+ -> f (Throws e m a)+ -> Throws e m' b+insideTf = (Throws .) . (. fmap hideException)++-- | Variant 'insideT'.+insideTf2+ :: (Functor f, Functor f')+ => (f (f' (m a)) -> m' b)+ -> f (f' (Throws e m a))+ -> Throws e m' b+insideTf2 = (Throws .) . (. fmap (fmap hideException))++-- | Generalized 'liftT2'.+insideT2+ :: (m1 a -> m2 b -> m3 c)+ -> Throws e m1 a -> Throws e m2 b -> Throws e m3 c+insideT2 f m n = Throws $ f (hideException m) (hideException n)++-- | Generalized 'liftT3'.+insideT3+ :: (m1 a -> m2 b -> m3 c -> m4 d)+ -> Throws e m1 a -> Throws e m2 b -> Throws e m3 c -> Throws e m4 d+insideT3 f m n o =+ Throws $ f (hideException m) (hideException n) (hideException o)++-- | Join two exception tags in to one. Isn't restricted just to+-- 'Control.Monad.Catch.MonadThrow' instances.+joinT+ :: Throws e (Throws e m) a+ -> Throws e m a+joinT = hideException++-- | Join three exception tags in to one. Isn't restricted just to+-- 'Control.Monad.Catch.MonadThrow' instances.+joinT3+ :: Throws e (Throws e (Throws e m)) a+ -> Throws e m a+joinT3 = hideTwo++-- | Flip two outermost exception tags. Isn't restricted just to+-- 'Control.Monad.Catch.MonadThrow' instances.+flipT+ :: Throws e' (Throws e m) a+ -> Throws e (Throws e' m) a+flipT = throwsTwo . hideTwo++-- | Since @1.2.0.0@.+embedT :: (m a -> Throws e n b) -> Throws e m a -> Throws e n b+embedT = (. hideException)++-- | Lift operations with type similar to monadic bind. In example:+--+-- @+-- ('Control.Monad.>>=') :: 'Control.Monad.Monad' m => m a -> (a -> m b) -> m b+-- @+--+-- @+-- 'Prelude.catch'+-- :: 'System.IO.IO' a+-- -> ('Control.Exception.IOError' -> 'System.IO.IO' a)+-- -> 'System.IO.IO' a+-- @+--+-- @+-- 'Control.Exception.catch'+-- :: 'Control.Exception.Exception' e+-- => 'System.IO.IO' a -> (e -> 'System.IO.IO' a) -> 'System.IO.IO' a+-- @+--+-- Since @1.2.0.0@.+liftBindLike+ :: (m a -> (b -> m c) -> m d)+ -> Throws e m a+ -> (b -> Throws e m c)+ -> Throws e m d+liftBindLike f x g = throwsOne $ f (hideException x) (hideException . g)++-- | Lift operations with type similar to flipped monadic bind. In example:+--+-- @+-- ('Control.Monad.=<<') :: 'Control.Monad.Monad' m => (a -> m b) -> m a -> m b+-- @+--+-- @+-- 'Control.Exception.handle'+-- :: 'Control.Exception.Exception' e+-- => (e -> 'System.IO.IO' a) -> 'System.IO.IO' a -> 'System.IO.IO' a+-- @+--+-- Since @1.2.0.0@.+liftFlipBindLike+ :: ((a -> m b) -> m c -> m d)+ -> (a -> Throws e m b) -> Throws e m c -> Throws e m d+liftFlipBindLike f g x = Throws $ f (hideException . g) (hideException x)++-- | Lift klieisli composition like operations. In example:+--+-- @+-- ('Control.Monad.>=>')+-- :: 'Control.Monad.Monad' m => (a -> m b) -> (b -> m c) -> a -> m c+-- @+--+-- @+-- ('Control.Monad.<=<')+-- :: 'Control.Monad.Monad' m => (b -> m c) -> (a -> m b) -> a -> m c+-- @+--+-- Since @1.2.0.0@.+liftKleisliLike+ :: ((a -> m a') -> (b -> m b') -> c -> m c')+ -> (a -> Throws e m a') -> (b -> Throws e m b') -> c -> Throws e m c'+liftKleisliLike f g h = Throws . f (hideException . g) (hideException . h)
+ src/Control/Monad/TaggedException/Utilities.hs view
@@ -0,0 +1,187 @@+{-# LANGUAGE NoImplicitPrelude #-}+{-# LANGUAGE RankNTypes #-}+-- |+-- Module: $HEADER$+-- Description: MonadExceptionUtilities class and instances.+-- Copyright: (c) 2009 - 2014 Peter Trsko.+-- License: BSD3+--+-- Stability: provisional+-- Portability: non-portable (NoImplicitPrelude, RankNTypes)+--+-- Introduces 'MonadExceptionUtilities' type class that provides means for+-- overriding default implementation of functions like 'bracket'.+module Control.Monad.TaggedException.Utilities+ (+ bracket+ , bracket'+ , bracket_+ , bracketOnError+ , bracketOnError'+ , finally+ , finally'+ )+ where++import Control.Monad (Monad(return))+import Control.Exception (Exception)+import Data.Function (($), const)++import Control.Monad.Catch (MonadMask)+import qualified Control.Monad.Catch as Exceptions++import Control.Monad.TaggedException.Core+ ( liftT+ , onException+ , onException'+ )+import Control.Monad.TaggedException.Internal.Throws (Throws)+import qualified Control.Monad.TaggedException.Internal.Throws+ as Unsafe (liftMask)+++mask' :: MonadMask m => ((forall a. m a -> m a) -> m b) -> m b+mask' = Exceptions.mask++mask+ :: (Exception e, MonadMask m)+ => ((forall a. Throws e m a -> Throws e m a) -> Throws e m b)+ -> Throws e m b+mask = Unsafe.liftMask Exceptions.mask++-- | Run computation afeter another even if exception was thrown. See also+-- 'finally'', 'onException' and 'onException''.+--+-- Default implementation:+--+-- > m `finally` n = mask $ \ restore -> do+-- > r <- restore m `onException` n+-- > _ <- liftT n+-- > return r+finally+ :: (Exception e, MonadMask m)+ => Throws e m a+ -- ^ Computation to run first+ -> m b+ -- ^ Computation to run afterward (even if exception @e@ was raised)+ -> Throws e m a+ -- ^ Returns the result of the first computation+m `finally` n = mask $ \restore -> do+ r <- restore m `onException` n+ _ <- liftT n+ return r++-- | Run computation afeter another even if exception was thrown. See also+-- 'finally', 'onException' and 'onException''.+finally'+ :: MonadMask m+ => m a+ -- ^ Computation to run first+ -> m b+ -- ^ Computation to run afterward (even if some exception was raised)+ -> m a+ -- ^ Returns the result of the first computation+finally' = Exceptions.finally++-- | Run computation surrounded by acquire and release computations. The+-- release computation is executed even if \"in-between\" computation+-- raises exception. See also 'bracket'', 'bracket_', 'bracketOnError',+-- and 'bracketOnError''.+bracket+ :: (Exception e, MonadMask m)+ => m a+ -- ^ Computation to run before+ -> (a -> m b)+ -- ^ Computation to run after+ -> (a -> Throws e m c)+ -- ^ Computation to run in-between+ -> Throws e m c+ -- ^ Result of the in-between computation+bracket acq rel go = mask $ \ restore -> do+ x <- liftT acq+ r <- restore (go x) `onException` rel x+ _ <- liftT $ rel x+ return r++-- | Run computation surrounded by acquire and release computations. The+-- release computation is executed even if \"in-between\" computation+-- raises exception. See also 'bracket', 'bracket_', 'bracketOnError', and+-- 'bracketOnError''.+--+-- Default implementation:+--+-- > bracket' acq rel go = mask' $ \ restore -> do+-- > x <- acq+-- > r <- restore (go x) `onException'` rel x+-- > _ <- rel x+-- > return r+bracket'+ :: MonadMask m+ => m a+ -- ^ Computation to run before+ -> (a -> m b)+ -- ^ Computation to run after+ -> (a -> m c)+ -- ^ Computation to run in-between+ -> m c+ -- ^ Result of the in-between computation+bracket' = Exceptions.bracket++-- | Version of 'bracket' where \"after\" computation is executed only if+-- \"in-between\" computation raises exception.+--+-- Default implementation:+--+-- > bracketOnError acq rel go = mask $ \ restore -> do+-- > x <- liftT acq+-- > restore (go x) `onException` rel x+bracketOnError+ :: (Exception e, MonadMask m)+ => m a+ -- ^ Computation to run before+ -> (a -> m b)+ -- ^ Computation to run after if an exception was raised+ -> (a -> Throws e m c)+ -- ^ Computation to run in-between+ -> Throws e m c+ -- ^ Result of the in-between computation+bracketOnError acq rel go = mask $ \ restore -> do+ x <- liftT acq+ restore (go x) `onException` rel x++-- | Version of 'bracket' where \"after\" computation is executed only if+-- \"in-between\" computation raises exception.+--+-- Default implementation:+--+-- > bracketOnError' acq rel go = mask' $ \ restore -> do+-- > x <- liftT acq+-- > restore (go x) `onException'` rel x+bracketOnError'+ :: MonadMask m+ => m a+ -- ^ Computation to run before+ -> (a -> m b)+ -- ^ Computation to run after if an exception was raised+ -> (a -> m c)+ -- ^ Computation to run in-between+ -> m c+ -- ^ Result of the in-between computation+bracketOnError' acq rel go = mask' $ \ restore -> do+ x <- acq+ restore (go x) `onException'` rel x++-- | Variant of 'bracket'.+--+-- > bracket_ acq rel go = bracket acq (const rel) (const go)+bracket_+ :: (Exception e, MonadMask m)+ => m a+ -- ^ Computation to run before+ -> m b+ -- ^ Computation to run after+ -> Throws e m c+ -- ^ Computation to run in-between+ -> Throws e m c+ -- ^ Result of the in-between computation+bracket_ acq rel go = bracket acq (const rel) (const go)
+ tagged-exception-core.cabal view
@@ -0,0 +1,84 @@+Name: tagged-exception-core+Version: 2.0.0.0+Synopsis: Reflect exceptions using phantom types.+Description:+ This library provides interface similar to /extensible-exceptions/. It+ introduces @Throws@ monad transformer that uses phantom type to tag code that+ may raise exception. Intention is to make exceptions explicit and to enforce+ exception handling.+Homepage: https://github.com/trskop/tagged-exception+Bug-reports: https://github.com/trskop/tagged-exception/issues+Copyright: Copyright (c) 2009 - 2014, Peter Trsko+License: BSD3+License-file: LICENSE+Author: Peter Trsko+Maintainer: peter.trsko@gmail.com+Category:+ Control+ , Error Handling+ , Exceptions+ , Failure+ , Monad+ , Monads+ , Phantom Types++Build-type: Simple+Cabal-version: >= 1.10+-- Tested-with:+Extra-source-files: ChangeLog.md++Flag pedantic+ Description:+ Pass additional flags, including -Werror, to GHC during compilation.+ Default: False+ Manual: True++Flag base-ge-4_2+ Description: Depend on base >= 4.2 && < 4.6.+ Default: False++Library+ Hs-source-dirs: src+ Exposed-modules:+ Control.Monad.TaggedException+ , Control.Monad.TaggedException.Core+ , Control.Monad.TaggedException.Hidden+ , Control.Monad.TaggedException.Internal.Throws+ , Control.Monad.TaggedException.Unsafe+ , Control.Monad.TaggedException.Utilities++ Default-language: Haskell2010++ if flag(base-ge-4_2)+ Build-depends:+ base >= 4.2 && < 4.8+ else+ Build-depends:+ base >= 4 && < 4.2+ , extensible-exceptions >= 0.1.1.3+ Build-depends:+ exceptions > 0.6 && < 0.7+ -- ^ Interface of this package changed a lot between minor versions,+ -- therefore trying conservative approach. Dependency introduced in+ -- tagged-exception-core-2.0.0.0.+ , transformers >= 0.2 && < 0.4+ , mmorph >= 1.0.0 && < 1.1+ -- ^ Dependency introduced in tagged-exception-core-1.2.0.0.++ if impl(ghc >= 7.8.1)+ CPP-options: -DKIND_POLYMORPHIC_TYPEABLE++ GHC-options: -Wall+ if impl(GHC >= 6.8)+ GHC-options: -fwarn-tabs+ if impl(GHC >= 7.2)+ GHC-options: -fwarn-identities+ if flag(pedantic)+ GHC-options:+ -fwarn-implicit-prelude+ -fwarn-missing-import-lists+ -Werror++source-repository head+ type: git+ location: git://github.com/trskop/tagged-exception.git