packages feed

explicit-exception 0.0.2 → 0.1

raw patch · 4 files changed

+114/−30 lines, 4 filesdep +transformersdep −mtlPVP ok

version bump matches the API change (PVP)

Dependencies added: transformers

Dependencies removed: mtl

API changes (from Hackage documentation)

+ Control.Monad.Exception.Asynchronous: mapException :: (e0 -> e1) -> Exceptional e0 a -> Exceptional e1 a
+ Control.Monad.Exception.Asynchronous: mapExceptional :: (e0 -> e1) -> (a -> b) -> Exceptional e0 a -> Exceptional e1 b
+ Control.Monad.Exception.Asynchronous: maybeAbort :: Exceptional e a -> Maybe e -> Exceptional e a
+ Control.Monad.Exception.Asynchronous: simultaneousBind :: Exceptional e a -> (a -> Exceptional e b) -> Exceptional e b
+ Control.Monad.Exception.Asynchronous: simultaneousBindM :: (Monad m) => m (Exceptional e a) -> (a -> m (Exceptional e b)) -> m (Exceptional e b)
+ Control.Monad.Exception.Asynchronous: swapToAsynchronousSynchronous :: Exceptional e1 (Exceptional e0 a) -> Exceptional e0 (Exceptional e1 a)
+ Control.Monad.Exception.Asynchronous: swapToSynchronousAsynchronous :: Exceptional e0 (Exceptional e1 a) -> Exceptional e1 (Exceptional e0 a)

Files

explicit-exception.cabal view
@@ -1,11 +1,10 @@ Name:             explicit-exception-Version:          0.0.2+Version:          0.1 License:          BSD3 License-File:     LICENSE Author:           Henning Thielemann <haskell@henning-thielemann.de> Maintainer:       Henning Thielemann <haskell@henning-thielemann.de> Homepage:         http://www.haskell.org/haskellwiki/Exception-Package-URL:      http://code.haskell.org/explicit-exception/ Category:         Control Stability:        Experimental Synopsis:         Exceptions which are explicit in the type signature.@@ -37,11 +36,20 @@    However note that freeing resources in case of an error is dangerous    and may cause further damage. Tested-With:       GHC==6.8.2-Cabal-Version:     >=1.2+Cabal-Version:     >=1.6 Build-Type:        Simple +Source-Repository head+  type:     darcs+  location: http://code.haskell.org/explicit-exception/++Source-Repository this+  type:     darcs+  location: http://code.haskell.org/explicit-exception/+  tag:      0.1+ Library-  Build-Depends: base >= 2, mtl+  Build-Depends: base >= 2, transformers >=0.0 && <0.1    GHC-Options:      -Wall   Hs-Source-Dirs:   src
src/Control/Monad/Exception/Asynchronous.hs view
@@ -1,6 +1,6 @@ {- | Asynchronous exceptions can occur during the construction of a lazy data structure.-They are represent by a lazy data structure itself.+They are represented by a lazy data structure itself.   TODO:@@ -34,11 +34,13 @@ If you evaluate the exception part, then the result value is certainly computed completely. -However, we cannot provide functions-that combine several 'Exceptional' values,+However, we cannot provide general 'Monad' functionality due to the very different ways of combining the results of type @a@. It is recommended to process the result value in an application specific way, and after consumption of the result, throw a synchronous exception using 'toSynchronous'.++Maybe in the future we provide a monad instance+which considers subsequent actions as simultaneous processes on a lazy data structure. -} data Exceptional e a =    Exceptional {exception :: Maybe e, result :: a}@@ -151,14 +153,14 @@    Exceptional e [a] -> Exceptional e [b] -> Exceptional e [c] zipWith f (Exceptional ea a0) (Exceptional eb b0) =    let recourse (a:as) (b:bs) =-          fmap (f a b :) (recurseF as bs)+          fmap (f a b :) (recourseF as bs)        recourse as _ =           Exceptional (case as of [] -> mplus ea eb; _ -> eb) []-       recurseF as bs = force $ recourse as bs-   in  recurseF a0 b0+       recourseF as bs = force $ recourse as bs+   in  recourseF a0 b0  -infixr 1 `append`, `continue`+infixr 1 `append`, `continue`, `maybeAbort`  {- | This is an example for application specific handling of result values.@@ -186,32 +188,61 @@       Just _  -> Exceptional ea mempty       Nothing -> b +maybeAbort ::+   Exceptional e a -> Maybe e -> Exceptional e a+maybeAbort ~(Exceptional ea a) eb =+   Exceptional (mplus ea eb) a + {- | construct Exceptional constructor lazily -} force :: Exceptional e a -> Exceptional e a force ~(Exceptional e a) = Exceptional e a +mapException :: (e0 -> e1) -> Exceptional e0 a -> Exceptional e1 a+mapException f ~(Exceptional e a) = Exceptional (fmap f e) a -{--catch :: Exceptional e0 a -> (e0 -> Exceptional e1 a) -> Exceptional e1 a-catch x handler =-   case x of-      Success a   -> Success a-      Exception e -> handler e--}+mapExceptional :: (e0 -> e1) -> (a -> b) -> Exceptional e0 a -> Exceptional e1 b+mapExceptional f g ~(Exceptional e a) = Exceptional (fmap f e) (g a)  instance Functor (Exceptional e) where    fmap f ~(Exceptional e a) = Exceptional e (f a) -{--Foldable instance would allow to strip off the exception too easily. -instance Foldable (Exceptional e) where+infixr 1 `simultaneousBind`, `simultaneousBindM` +{- |+I consider both actions to process the data simultaneously through lazy evaluation.+If the second one fails too, it must have encountered an exception+in the data that was successfully emitted by the first action,+and thus the exception of the second action is probably earlier. -I like the methods of traversable, but Traversable instance requires Foldable instance+We cannot check in general whether the two exception occur at the same time,+e.g. the second one might occur since the first occured and left an invalid structure.+In this case we should emit the first exception, not the second one.+Because of this I expect that this function is not particularly useful.+Otherwise it could be used as bind operation for a monad instance.+-}+{-# DEPRECATED simultaneousBind, simultaneousBindM "Check whether this function is really what you need. It generates an unreasonable exception when the second exception is caused by the first one." #-}+simultaneousBind :: Exceptional e a -> (a -> Exceptional e b) -> Exceptional e b+simultaneousBind ~(Exceptional mea a) actB =+   let Exceptional meb b = actB a+   in  Exceptional (mplus meb mea) b -instance Traversable (Exceptional e) where+simultaneousBindM :: (Monad m) => m (Exceptional e a) -> (a -> m (Exceptional e b)) -> m (Exceptional e b)+simultaneousBindM actA actB =+   do Exceptional mea a <- actA+      Exceptional meb b <- actB a+      return (Exceptional (mplus meb mea) b)+++-- instance Foldable (Exceptional e) where++-- instance Traversable (Exceptional e) where++{- |+@Foldable@ instance would allow to strip off the exception too easily.++I like the methods of @Traversable@, but @Traversable@ instance requires @Foldable@ instance. -}  {-# INLINE traverse #-}@@ -236,7 +267,7 @@  {- instance Applicative (Exceptional e) where-   pure = Exceptional [] -- [Nothing]?+   pure = pure    f <*> x =       case f of          Exceptional e0 g ->@@ -244,7 +275,7 @@                Exceptional e1 y -> Exceptional (mplus e0 e1) (g y)  instance Monad (Exceptional e) where-   return = Exceptional [] -- [Nothing]?+   return = pure    fail _msg =       Exceptional          [Just (error "Asynchronous.fail exception")]@@ -254,8 +285,34 @@          Exceptional e0 y ->             case f y of                Exceptional e1 z -> Exceptional (e0 ++ e1) z+-} +{- |+Consider a file format consisting of a header and a data body.+The header can only be used if is read completely.+Its parsing might stop with an synchronous exception.+The data body can also be used if it is truncated by an exceptional event.+This is expressed by an asynchronous exception.+A loader for this file format can thus fail+by a synchronous and an asynchronous exception.+Surprisingly, both orders of nesting these two kinds of exceptional actions+are equally expressive.+This function converts to the form where the synchronous exception is the outer one.+-}+swapToSynchronousAsynchronous :: Exceptional e0 (Sync.Exceptional e1 a) -> Sync.Exceptional e1 (Exceptional e0 a)+swapToSynchronousAsynchronous ~(Exceptional e0 x) =+   fmap (Exceptional e0) x +swapToAsynchronousSynchronous :: Sync.Exceptional e1 (Exceptional e0 a) -> Exceptional e0 (Sync.Exceptional e1 a)+swapToAsynchronousSynchronous x =+   force $+   case x of+      Sync.Exception e1 -> pure $ Sync.throw e1+      Sync.Success s -> fmap Sync.Success s++++{- -- * Monad transformer  newtype ExceptionalT e m a =
src/Control/Monad/Exception/Synchronous.hs view
@@ -5,10 +5,10 @@ module Control.Monad.Exception.Synchronous where  import Control.Applicative (Applicative(pure, (<*>)))-import Control.Monad (liftM, )+import Control.Monad (liftM, {- MonadPlus(mzero, mplus), -}) import Control.Monad.Fix (MonadFix, mfix, )-import Control.Monad.Trans (MonadTrans, lift, )-import Control.Monad.Error (ErrorT(ErrorT, runErrorT))+import Control.Monad.Trans (MonadTrans, lift, {- MonadIO(liftIO), -} )+import Control.Monad.Trans.Error (ErrorT(ErrorT, runErrorT))  import Prelude hiding (catch, ) @@ -19,6 +19,8 @@ Like 'Either', but explicitly intended for handling of exceptional results. In contrast to 'Either' we do not support 'fail'. Calling 'fail' in the 'Exceptional' monad is an error.+This way, we do not require that an exception can be derived from a 'String',+yet, we require no constraint on the exception type at all. -} data Exceptional e a =      Success a@@ -125,8 +127,16 @@            a = f (unSuccess a)        in  a +{-+A MonadPlus instance would require another class, say DefaultException,+that provides a default exception used for @mzero@.+In Control.Monad.Error this is handled by the Error class.+Since String is a typical type used for exceptions -+shall there be a DefaultException String instance?+-}  + -- * Monad transformer  -- | like ErrorT, but ExceptionalT is the better name in order to distinguish from real (programming) errors@@ -257,3 +267,8 @@  instance MonadTrans (ExceptionalT e) where    lift m = ExceptionalT $ liftM Success m++{-+instance MonadIO m => MonadIO (ExceptionalT e m) where+   liftIO act = ExceptionalT $ liftIO $ liftM Success act+-}
src/Control/Monad/Label.hs view
@@ -7,6 +7,10 @@ while reading file \'foo.txt\' while loading document \'bar.doc\'\" using the functions in "Control.Monad.Exception.Label".++However, currently I believe that this datatype is unnecessary,+since you can extend exceptions by context information+using 'Control.Monad.Exception.Synchronous.mapException'. -} module Control.Monad.Label where @@ -15,8 +19,8 @@ import Control.Monad (MonadPlus, ap, ) import Control.Monad.Fix (MonadFix) import Control.Monad.Trans (MonadTrans, MonadIO)-import qualified Control.Monad.Reader as Reader-import Control.Monad.Reader (Reader, ReaderT(ReaderT), runReader, runReaderT, )+import qualified Control.Monad.Trans.Reader as Reader+import Control.Monad.Trans.Reader (Reader, ReaderT(ReaderT), runReader, runReaderT, ) import Control.Monad.Instances ()