packages feed

explicit-exception 0.1.3 → 0.1.4

raw patch · 4 files changed

+225/−69 lines, 4 filesPVP ok

version bump matches the API change (PVP)

API changes (from Hackage documentation)

+ Control.Monad.Exception.Asynchronous: ExceptionalT :: m (Exceptional e a) -> ExceptionalT e m a
+ Control.Monad.Exception.Asynchronous: bindT :: (Monad m, Monoid b) => ExceptionalT e m a -> (a -> ExceptionalT e m b) -> ExceptionalT e m b
+ Control.Monad.Exception.Asynchronous: eatNothing :: Exceptional (Maybe e) a -> Exceptional e a
+ Control.Monad.Exception.Asynchronous: eatNothingT :: (Monad m) => ExceptionalT (Maybe e) m a -> ExceptionalT e m a
+ Control.Monad.Exception.Asynchronous: forceT :: (Monad m) => ExceptionalT e m a -> ExceptionalT e m a
+ Control.Monad.Exception.Asynchronous: fromSynchronousMonoidT :: (Functor m, Monoid a) => ExceptionalT e m a -> ExceptionalT e m a
+ Control.Monad.Exception.Asynchronous: fromSynchronousT :: (Functor m) => a -> ExceptionalT e m a -> ExceptionalT e m a
+ Control.Monad.Exception.Asynchronous: instance (Functor m) => Functor (ExceptionalT e m)
+ Control.Monad.Exception.Asynchronous: instance (Monad m, Monoid a) => Monoid (ExceptionalT e m a)
+ Control.Monad.Exception.Asynchronous: manyMonoidT :: (Monad m, Monoid a) => ExceptionalT e m a -> ExceptionalT e m a
+ Control.Monad.Exception.Asynchronous: mapExceptionT :: (Monad m) => (e0 -> e1) -> ExceptionalT e0 m a -> ExceptionalT e1 m a
+ Control.Monad.Exception.Asynchronous: mapExceptionalT :: (m (Exceptional e0 a) -> n (Exceptional e1 b)) -> ExceptionalT e0 m a -> ExceptionalT e1 n b
+ Control.Monad.Exception.Asynchronous: newtype ExceptionalT e m a
+ Control.Monad.Exception.Asynchronous: runExceptionalT :: ExceptionalT e m a -> m (Exceptional e a)
+ Control.Monad.Exception.Asynchronous: throwMonoidT :: (Monad m, Monoid a) => e -> ExceptionalT e m a
+ Control.Monad.Exception.Synchronous: manyMonoidT :: (Monad m, Monoid a) => (e0 -> Maybe e1) -> ExceptionalT e0 m a -> ExceptionalT e1 m a

Files

explicit-exception.cabal view
@@ -1,5 +1,5 @@ Name:             explicit-exception-Version:          0.1.3+Version:          0.1.4 License:          BSD3 License-File:     LICENSE Author:           Henning Thielemann <haskell@henning-thielemann.de>@@ -46,7 +46,7 @@ Source-Repository this   type:     darcs   location: http://code.haskell.org/explicit-exception/-  tag:      0.1.3+  tag:      0.1.4  Library   Build-Depends: base >= 2, transformers >=0.0 && <0.2
src/Control/Monad/Exception/Asynchronous.hs view
@@ -5,7 +5,13 @@  TODO: -* Check whether laziness behaviour is reasonable.+* Is it reasonable, that many functions match the exception lazily?+  Or is lazy decoupling an operation that shall always be done explicitly?+* Is the Null type appropriate anywhere?+  Should it be better a Monoid type with mempty?+  Shall Monoid.mempty be the default, or functions with explicit default values?+* Shall we replace Monad constraint by Functor constraint,+  where we only need liftM? -} module Control.Monad.Exception.Asynchronous (    Exceptional(..),@@ -17,8 +23,7 @@    toSynchronous,    throw,    throwMonoid,-   manySynchronousT,-   processToSynchronousT_,+   eatNothing,    zipWith,    append,    continue,@@ -36,13 +41,26 @@    swapToSynchronousAsynchronous,    swapToAsynchronousSynchronous, +   ExceptionalT(..),+   fromSynchronousT,+   fromSynchronousMonoidT,+   forceT,+   mapExceptionT,+   mapExceptionalT,+   throwMonoidT,+   eatNothingT,+   bindT,+   manySynchronousT,+   manyMonoidT,+   processToSynchronousT_,+    appendM,    continueM,    ) where  import qualified Control.Monad.Exception.Synchronous as Sync -import Control.Monad (mplus, liftM, )+import Control.Monad (mplus, liftM, join, ) import Control.Applicative (Applicative, liftA, ) {- import Data.Traversable (Traversable, )@@ -111,61 +129,26 @@    maybe (Sync.Success a) Sync.Exception me  +{- |+I think in most cases we want throwMonoid,+thus we can replace 'throw' by 'throwMonoid'.+-} throw :: e -> Exceptional e () throw e = broken e ()  throwMonoid :: Monoid a => e -> Exceptional e a throwMonoid e = broken e mempty -- {- |-Repeat an action with synchronous exceptions until an exception occurs.-Combine all atomic results using the @bind@ function.-It may be @cons = (:)@ and @empty = []@ for @b@ being a list type.-The @defer@ function may be @id@-or @unsafeInterleaveIO@ for lazy read operations.-The exception is returned as asynchronous exception.--}-manySynchronousT :: (Monad m) =>-   (m (Exceptional e b) -> m (Exceptional e b))-                           {- ^ @defer@ function -} ->-   (a -> b -> b)           {- ^ @cons@ function -} ->-   b                       {- ^ @empty@ -} ->-   Sync.ExceptionalT e m a {- ^ atomic action to repeat -} ->-   m (Exceptional e b)-manySynchronousT defer cons empty action =-   let recourse =-          liftM force $ defer $-          do r <- Sync.tryT action-             case r of-                Sync.Exception e -> return (Exceptional (Just e) empty)-                Sync.Success x   -> liftM (fmap (cons x)) recourse-   in  recourse--{- |-Scan @x@ using the @decons@ function-and run an action with synchronous exceptions for each element fetched from @x@.-Each invocation of an element action may stop this function-due to an exception.-If all element action can be performed successfully-and if there is an asynchronous exception-then at the end this exception is raised as synchronous exception.-@decons@ function might be @viewL@.+You might use an exception of type @Maybe e@ in 'manyMonoidT'+in order to stop the loop.+After finishing the loop you will want+to turn the @Nothing@ exception into a success.+This is achieved by this function. -}-processToSynchronousT_ :: (Monad m) =>-   (b -> Maybe (a,b))  {- ^ decons function -} ->-   (a -> Sync.ExceptionalT e m ())-                       {- ^ action that is run for each element fetched from @x@ -} ->-   Exceptional e b     {- ^ value @x@ of type @b@ with asynchronous exception -} ->-   Sync.ExceptionalT e m ()-processToSynchronousT_ decons action (Exceptional me x) =-   let recourse b0 =-          maybe-             (maybe (return ()) Sync.throwT me)-             (\(a,b1) -> action a >> recourse b1)-             (decons b0)-   in  recourse x+eatNothing :: Exceptional (Maybe e) a -> Exceptional e a+eatNothing (Exceptional e a) =+   Exceptional (join e) a   -- ** handling of special result types@@ -250,8 +233,6 @@  {- fmap (f.g) = fmap f . fmap g-- -} instance Functor (Exceptional e) where    fmap f ~(Exceptional e a) = Exceptional e (f a)@@ -369,30 +350,41 @@       Sync.Success s -> fmap Sync.Success s  -{---- * Monad transformer+-- * Monad/Monoid transformer +{- |+In contrast to synchronous exceptions,+the asynchronous monad transformer is not quite a monad.+You must use the 'Monoid' interface or 'bindT' instead.+-} newtype ExceptionalT e m a =    ExceptionalT {runExceptionalT :: m (Exceptional e a)}   fromSynchronousT :: Functor m =>    a -> Sync.ExceptionalT e m a -> ExceptionalT e m a-fromSynchronousT deflt (Sync.ExceptionalT mx) =-   ExceptionalT $ fmap (fromSynchronous deflt) mx----throwT :: (Monad m) =>-   e -> ExceptionalT e m ()-throwT = ExceptionalT . return . throw+fromSynchronousT deflt =+   ExceptionalT .+   fmap (fromSynchronous deflt) .+   Sync.runExceptionalT +fromSynchronousMonoidT :: (Functor m, Monoid a) =>+   Sync.ExceptionalT e m a -> ExceptionalT e m a+fromSynchronousMonoidT =+   fromSynchronousT mempty   instance Functor m => Functor (ExceptionalT e m) where    fmap f (ExceptionalT x) =       ExceptionalT (fmap (fmap f) x) +instance (Monad m, Monoid a) => Monoid (ExceptionalT e m a) where+   mempty = ExceptionalT $ return mempty+   mappend x y =+      ExceptionalT $+      appendM (runExceptionalT x) (runExceptionalT y)++{- instance Applicative m => Applicative (ExceptionalT e m) where    pure = ExceptionalT . pure . pure    ExceptionalT f <*> ExceptionalT x =@@ -407,6 +399,58 @@          return $ Exceptional (ex ++ ey) y -} ++{- |+see 'force'+-}+forceT :: Monad m => ExceptionalT e m a -> ExceptionalT e m a+forceT =+   ExceptionalT . liftM force . runExceptionalT++mapExceptionT :: (Monad m) =>+   (e0 -> e1) ->+   ExceptionalT e0 m a ->+   ExceptionalT e1 m a+mapExceptionT f =+   ExceptionalT . liftM (mapException f) . runExceptionalT++mapExceptionalT ::+   (m (Exceptional e0 a) -> n (Exceptional e1 b)) ->+   ExceptionalT e0 m a -> ExceptionalT e1 n b+mapExceptionalT f =+   ExceptionalT . f . runExceptionalT+++throwMonoidT :: (Monad m, Monoid a) =>+   e -> ExceptionalT e m a+throwMonoidT = ExceptionalT . return . throwMonoid+++eatNothingT :: Monad m =>+   ExceptionalT (Maybe e) m a -> ExceptionalT e m a+eatNothingT =+   mapExceptionalT (liftM eatNothing)+++infixl 1 `bindT`++{- |+The monadic bind operation.+It cannot be made an instance of the Monad class method @(>>=)@+since it requires a default return value+in case the first action fails.+We get this default value by the 'Monoid' method 'mempty'.+-}+bindT :: (Monad m, Monoid b) =>+   ExceptionalT e m a ->+   (a -> ExceptionalT e m b) ->+   ExceptionalT e m b+bindT x y =+   ExceptionalT $+   runExceptionalT x >>= \r ->+   runExceptionalT $ maybe (y $ result r) throwMonoidT (exception r)++ infixr 1 {- `bindM`, -} `appendM`, `continueM`  {-@@ -435,3 +479,77 @@    Maybe e -> m (Exceptional e a) -> m (Exceptional e a) continueMPlain x y =    maybe y (return . throwMonoid) x+++{- |+Repeat an action with synchronous exceptions until an exception occurs.+Combine all atomic results using the @bind@ function.+It may be @cons = (:)@ and @empty = []@ for @b@ being a list type.+The @defer@ function may be @id@+or @unsafeInterleaveIO@ for lazy read operations.+The exception is returned as asynchronous exception.+-}+manySynchronousT :: (Monad m) =>+   (m (Exceptional e b) -> m (Exceptional e b))+                           {- ^ @defer@ function -} ->+   (a -> b -> b)           {- ^ @cons@ function -} ->+   b                       {- ^ @empty@ -} ->+   Sync.ExceptionalT e m a {- ^ atomic action to repeat -} ->+   m (Exceptional e b)+manySynchronousT defer cons empty action =+   let recourse =+          liftM force $ defer $+          do r <- Sync.tryT action+             case r of+                Sync.Exception e -> return (Exceptional (Just e) empty)+                Sync.Success x   -> liftM (fmap (cons x)) recourse+   in  recourse++{-# DEPRECATED manySynchronousT "use manyMonoidT with appropriate Monad like LazyIO and result Monoid like Endo instead" #-}++{- |+We advise to use the Endo Monoid+when you want to read a series of characters into a list.+This means you use the difference lists technique+in order to build the list, which is efficient.++> import Data.Monoid (Endo, appEndo, )+> import Control.Exception (try, )+> import qualified Control.Monad.Exception.Synchronous as Sync++> fmap (flip appEndo []) $ manyMonoidT (fromSynchronousMonoidT $ fmap (Endo . (:)) $ Sync.fromEitherT $ try getChar)++If you want Lazy IO you must additionally convert @getChar@ to LazyIO monad.+-}+manyMonoidT :: (Monad m, Monoid a) =>+   ExceptionalT e m a {- ^ atomic action to repeat -} ->+   ExceptionalT e m a+manyMonoidT act =+   let -- like fmap, but doesn't require Functor instance of @m@+       customFmap f = mapExceptionalT (liftM (fmap f))+       go = act `bindT` \r -> customFmap (mappend r) go+   in  go++{- |+Scan @x@ using the @decons@ function+and run an action with synchronous exceptions for each element fetched from @x@.+Each invocation of an element action may stop this function+due to an exception.+If all element actions can be performed successfully+and if there is an asynchronous exception+then at the end this exception is raised as synchronous exception.+@decons@ function might be @Data.List.HT.viewL@.+-}+processToSynchronousT_ :: (Monad m) =>+   (b -> Maybe (a,b))  {- ^ decons function -} ->+   (a -> Sync.ExceptionalT e m ())+                       {- ^ action that is run for each element fetched from @x@ -} ->+   Exceptional e b     {- ^ value @x@ of type @b@ with asynchronous exception -} ->+   Sync.ExceptionalT e m ()+processToSynchronousT_ decons action (Exceptional me x) =+   let recourse b0 =+          maybe+             (maybe (return ()) Sync.throwT me)+             (\(a,b1) -> action a >> recourse b1)+             (decons b0)+   in  recourse x
src/Control/Monad/Exception/Synchronous.hs view
@@ -1,6 +1,31 @@ {- | Synchronous exceptions immediately abort a series of computations. We provide monads for describing this behaviour.+In contrast to ErrorT from @mtl@ or @transformers@ package+we do not pose restrictions on the exception type.++How to tell, that a function can possibly throw more than one (kind of) exception?++If you would use the exception type @(Either ParserException IOError)@+then this is different from @(Either IOError ParserException)@.+Thus we recommned using type classes for exceptions.+Then you can use one type containing all exceptions in an application,+but the type signature still tells which exceptions are actually possible.+Examples:++> parser :: ParserException e => ExceptionalT e ParserMonad a+>+> getLine :: IOException e => ExceptionalT e IO String+>+> fileParser :: (ParserException e, IOException e) => ExceptionalT e IO String++Unfortunately, this way you cannot remove single exceptions+from the constraints by catching them.+You can only remove all of them using 'resolve' or none.+For a more advanced approach,+that allows removing exceptions constraints+by some non-Haskell-98 type hackery,+see the exception package by Joseph Iborra. -} module Control.Monad.Exception.Synchronous (    Exceptional(..),@@ -29,6 +54,7 @@    resolveT,    tryT,    manyT,+   manyMonoidT,    ) where  import Control.Applicative (Applicative(pure, (<*>)))@@ -36,6 +62,7 @@ import Control.Monad.Fix (MonadFix, mfix, ) import Control.Monad.Trans (MonadTrans, lift, {- MonadIO(liftIO), -} ) import Control.Monad.Trans.Error (ErrorT(ErrorT, runErrorT))+import Data.Monoid(Monoid, mappend, mempty, Endo(Endo, appEndo), )  import Prelude hiding (catch, ) @@ -281,13 +308,23 @@    ExceptionalT e0 m a     {- ^ atomic action to repeat -} ->    ExceptionalT e1 m b manyT handler cons empty action =+   liftM (flip appEndo empty) $+   manyMonoidT handler $+   liftM (Endo . cons) action++manyMonoidT :: (Monad m, Monoid a) =>+   (e0 -> Maybe e1)        {- ^ exception handler -} ->+   ExceptionalT e0 m a     {- ^ atomic action to repeat -} ->+   ExceptionalT e1 m a+manyMonoidT handler action =    let recourse =           do r <- lift $ tryT action              case r of-                Exception e -> maybe (return empty) throwT (handler e)-                Success x   -> liftM (cons x) recourse+                -- Exception e -> maybe (return empty) throwT (handler e)+                -- more lazy+                Exception e -> ExceptionalT $ return $ maybe (Success mempty) throw (handler e)+                Success x   -> liftM (mappend x) recourse    in  recourse-   
src/System/IO/Exception/TextFile.hs view
@@ -33,13 +33,14 @@ getContentsSynchronous :: Handle -> EIO String getContentsSynchronous h =    Sync.manyT-      -- candidate for toMaybe+      -- candidate for toMaybe from utility-ht       (\e -> if isEOFError e then Nothing else Just e)       (:) [] (getChar h)  {- | This calls 'unsafeInterleaveIO'. Maybe we should also attach 'unsafe' to this function name?+We should use the LazyIO type and manyT here. -} getContentsAsynchronous :: Handle -> SIO (Async.Exceptional IOException String) getContentsAsynchronous h =