packages feed

explicit-exception 0.1.4 → 0.1.5

raw patch · 10 files changed

+311/−20 lines, 10 filesdep +applicativedep +bytestringdep +special-functorsdep ~basedep ~transformersnew-component:exe:ee-tarnew-component:exe:ee-testnew-component:exe:ee-unzipnew-component:exe:ee-writerPVP: major bump suggested

API removals or changes: PVP suggests a major version bump

Dependencies added: applicative, bytestring, special-functors, tar

Dependency ranges changed: base, transformers

API changes (from Hackage documentation)

- Control.Monad.Exception.Asynchronous: instance (Functor m) => Functor (ExceptionalT e m)
- Control.Monad.Exception.Asynchronous: instance (Monoid a) => Monoid (Exceptional e a)
- Control.Monad.Exception.Synchronous: instance (Applicative m) => Applicative (ExceptionalT e m)
- Control.Monad.Exception.Synchronous: instance (Functor m) => Functor (ExceptionalT e m)
- Control.Monad.Exception.Synchronous: instance (Monad m) => Monad (ExceptionalT e m)
- Control.Monad.Exception.Synchronous: instance (MonadFix m) => MonadFix (ExceptionalT e m)
+ Control.Monad.Exception.Asynchronous: instance Functor m => Functor (ExceptionalT e m)
+ Control.Monad.Exception.Asynchronous: instance Monoid a => Monoid (Exceptional e a)
+ Control.Monad.Exception.Synchronous: instance Applicative m => Applicative (ExceptionalT e m)
+ Control.Monad.Exception.Synchronous: instance Functor m => Functor (ExceptionalT e m)
+ Control.Monad.Exception.Synchronous: instance Monad m => Monad (ExceptionalT e m)
+ Control.Monad.Exception.Synchronous: instance MonadFix m => MonadFix (ExceptionalT e m)
- Control.Monad.Exception.Asynchronous: append :: (Monoid a) => Exceptional e a -> Exceptional e a -> Exceptional e a
+ Control.Monad.Exception.Asynchronous: append :: Monoid a => Exceptional e a -> Exceptional e a -> Exceptional e a
- Control.Monad.Exception.Asynchronous: continue :: (Monoid a) => Maybe e -> Exceptional e a -> Exceptional e a
+ Control.Monad.Exception.Asynchronous: continue :: Monoid a => Maybe e -> Exceptional 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: 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: forceT :: Monad m => ExceptionalT e m a -> ExceptionalT e m a
- Control.Monad.Exception.Asynchronous: fromSynchronousMonoid :: (Monoid a) => Exceptional e a -> Exceptional e a
+ Control.Monad.Exception.Asynchronous: fromSynchronousMonoid :: Monoid a => Exceptional e a -> Exceptional e a
- Control.Monad.Exception.Asynchronous: fromSynchronousT :: (Functor m) => 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: manySynchronousT :: (Monad m) => (m (Exceptional e b) -> m (Exceptional e b)) -> (a -> b -> b) -> b -> ExceptionalT e m a -> m (Exceptional e b)
+ Control.Monad.Exception.Asynchronous: manySynchronousT :: Monad m => (m (Exceptional e b) -> m (Exceptional e b)) -> (a -> b -> b) -> b -> ExceptionalT e m a -> m (Exceptional e b)
- Control.Monad.Exception.Asynchronous: mapExceptionT :: (Monad m) => (e0 -> e1) -> ExceptionalT e0 m a -> ExceptionalT e1 m a
+ Control.Monad.Exception.Asynchronous: mapExceptionT :: Monad m => (e0 -> e1) -> ExceptionalT e0 m a -> ExceptionalT e1 m a
- Control.Monad.Exception.Asynchronous: mapM :: (Monad m) => (a -> m b) -> Exceptional e a -> m (Exceptional e b)
+ Control.Monad.Exception.Asynchronous: mapM :: Monad m => (a -> m b) -> Exceptional e a -> m (Exceptional e b)
- Control.Monad.Exception.Asynchronous: processToSynchronousT_ :: (Monad m) => (b -> Maybe (a, b)) -> (a -> ExceptionalT e m ()) -> Exceptional e b -> ExceptionalT e m ()
+ Control.Monad.Exception.Asynchronous: processToSynchronousT_ :: Monad m => (b -> Maybe (a, b)) -> (a -> ExceptionalT e m ()) -> Exceptional e b -> ExceptionalT e m ()
- Control.Monad.Exception.Asynchronous: sequence :: (Monad m) => Exceptional e (m a) -> m (Exceptional e a)
+ Control.Monad.Exception.Asynchronous: sequence :: Monad m => Exceptional e (m a) -> m (Exceptional e a)
- Control.Monad.Exception.Asynchronous: sequenceA :: (Applicative f) => Exceptional e (f a) -> f (Exceptional e a)
+ Control.Monad.Exception.Asynchronous: sequenceA :: Applicative f => Exceptional e (f a) -> f (Exceptional e a)
- Control.Monad.Exception.Asynchronous: sequenceF :: (Functor f) => Exceptional e (f a) -> f (Exceptional e a)
+ Control.Monad.Exception.Asynchronous: sequenceF :: Functor f => Exceptional e (f a) -> f (Exceptional e a)
- Control.Monad.Exception.Asynchronous: simultaneousBindM :: (Monad m) => m (Exceptional e a) -> (a -> m (Exceptional e b)) -> m (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: throwMonoid :: (Monoid a) => e -> Exceptional e a
+ Control.Monad.Exception.Asynchronous: throwMonoid :: Monoid a => e -> Exceptional e a
- Control.Monad.Exception.Asynchronous: traverse :: (Applicative f) => (a -> f b) -> Exceptional e a -> f (Exceptional e b)
+ Control.Monad.Exception.Asynchronous: traverse :: Applicative f => (a -> f b) -> Exceptional e a -> f (Exceptional e b)
- Control.Monad.Exception.Synchronous: assertT :: (Monad m) => e -> Bool -> ExceptionalT e m ()
+ Control.Monad.Exception.Synchronous: assertT :: Monad m => e -> Bool -> ExceptionalT e m ()
- Control.Monad.Exception.Synchronous: bracketT :: (Monad m) => ExceptionalT e m h -> (h -> ExceptionalT e m ()) -> (h -> ExceptionalT e m a) -> ExceptionalT e m a
+ Control.Monad.Exception.Synchronous: bracketT :: Monad m => ExceptionalT e m h -> (h -> ExceptionalT e m ()) -> (h -> ExceptionalT e m a) -> ExceptionalT e m a
- Control.Monad.Exception.Synchronous: catchT :: (Monad m) => ExceptionalT e0 m a -> (e0 -> ExceptionalT e1 m a) -> ExceptionalT e1 m a
+ Control.Monad.Exception.Synchronous: catchT :: Monad m => ExceptionalT e0 m a -> (e0 -> ExceptionalT e1 m a) -> ExceptionalT e1 m a
- Control.Monad.Exception.Synchronous: forceT :: (Monad m) => ExceptionalT e m a -> ExceptionalT e m a
+ Control.Monad.Exception.Synchronous: forceT :: Monad m => ExceptionalT e m a -> ExceptionalT e m a
- Control.Monad.Exception.Synchronous: fromEitherT :: (Monad m) => m (Either e a) -> ExceptionalT e m a
+ Control.Monad.Exception.Synchronous: fromEitherT :: Monad m => m (Either e a) -> ExceptionalT e m a
- Control.Monad.Exception.Synchronous: fromErrorT :: (Monad m) => ErrorT e m a -> ExceptionalT e m a
+ Control.Monad.Exception.Synchronous: fromErrorT :: Monad m => ErrorT e m a -> ExceptionalT e m a
- Control.Monad.Exception.Synchronous: manyT :: (Monad m) => (e0 -> Maybe e1) -> (a -> b -> b) -> b -> ExceptionalT e0 m a -> ExceptionalT e1 m b
+ Control.Monad.Exception.Synchronous: manyT :: Monad m => (e0 -> Maybe e1) -> (a -> b -> b) -> b -> ExceptionalT e0 m a -> ExceptionalT e1 m b
- Control.Monad.Exception.Synchronous: mapExceptionT :: (Monad m) => (e0 -> e1) -> ExceptionalT e0 m a -> ExceptionalT e1 m a
+ Control.Monad.Exception.Synchronous: mapExceptionT :: Monad m => (e0 -> e1) -> ExceptionalT e0 m a -> ExceptionalT e1 m a
- Control.Monad.Exception.Synchronous: resolveT :: (Monad m) => (e -> m a) -> ExceptionalT e m a -> m a
+ Control.Monad.Exception.Synchronous: resolveT :: Monad m => (e -> m a) -> ExceptionalT e m a -> m a
- Control.Monad.Exception.Synchronous: throwT :: (Monad m) => e -> ExceptionalT e m a
+ Control.Monad.Exception.Synchronous: throwT :: Monad m => e -> ExceptionalT e m a
- Control.Monad.Exception.Synchronous: toEitherT :: (Monad m) => ExceptionalT e m a -> m (Either e a)
+ Control.Monad.Exception.Synchronous: toEitherT :: Monad m => ExceptionalT e m a -> m (Either e a)
- Control.Monad.Exception.Synchronous: toErrorT :: (Monad m) => ExceptionalT e m a -> ErrorT e m a
+ Control.Monad.Exception.Synchronous: toErrorT :: Monad m => ExceptionalT e m a -> ErrorT e m a
- Control.Monad.Exception.Synchronous: tryT :: (Monad m) => ExceptionalT e m a -> m (Exceptional e a)
+ Control.Monad.Exception.Synchronous: tryT :: Monad m => ExceptionalT e m a -> m (Exceptional e a)

Files

explicit-exception.cabal view
@@ -1,5 +1,5 @@ Name:             explicit-exception-Version:          0.1.4+Version:          0.1.5 License:          BSD3 License-File:     LICENSE Author:           Henning Thielemann <haskell@henning-thielemann.de>@@ -46,23 +46,79 @@ Source-Repository this   type:     darcs   location: http://code.haskell.org/explicit-exception/-  tag:      0.1.4+  tag:      0.1.5 +Flag buildTests+  description: Build test suite+  default:     False++Flag splitBase+  description: Choose the smaller, split-up base package from version 2 on.++ Library-  Build-Depends: base >= 2, transformers >=0.0 && <0.2+  Build-Depends: transformers >=0.2 && <0.3+  If impl(jhc)+    Build-Depends:+      applicative >=1.0 && <1.1,+      base >= 1 && <2+  Else+    If flag(splitBase)+      Build-Depends: base >= 2 && <5+    Else+      Build-Depends:+        special-functors >=1.0 && <1.1,+        base >= 1 && <2    GHC-Options:      -Wall   Hs-Source-Dirs:   src   Exposed-Modules:     Control.Monad.Exception.Asynchronous     Control.Monad.Exception.Synchronous-  Other-Modules:-    Control.Monad.Exception.Warning-    Control.Monad.Exception.Label-    Control.Monad.Label-    System.IO.Straight-    System.IO.Exception.File-    System.IO.Exception.BinaryFile-    System.IO.Exception.TextFile+  If !impl(jhc)+    Other-Modules:+      Control.Monad.Exception.Warning+      Control.Monad.Exception.Label+      Control.Monad.Label+      System.IO.Straight+      System.IO.Exception.File+      System.IO.Exception.BinaryFile+      System.IO.Exception.TextFile --    System.IO.Exception.Std --    Debug.Error++Executable ee-tar+  If flag(buildTests)+    Build-Depends:+      bytestring >=0.9.0.1 && <0.10,+      tar >=0.3 && <0.4+  Else+    Buildable: False+  GHC-Options: -Wall+  Hs-Source-Dirs: src, spaceleak+  Main-Is: Tar.hs++Executable ee-test+  If flag(buildTests)+    Build-Depends:+      bytestring >=0.9.0.1 && <0.10+  Else+    Buildable: False+  GHC-Options: -Wall+  Hs-Source-Dirs: src, spaceleak+  Main-Is: Example.hs++Executable ee-unzip+  If !flag(buildTests)+    Buildable: False+  GHC-Options: -Wall+  Hs-Source-Dirs: spaceleak+  Main-Is: Unzip.hs++Executable ee-writer+  If !flag(buildTests)+    Buildable: False+    Buildable: False+  GHC-Options: -Wall+  Hs-Source-Dirs: spaceleak+  Main-Is: Writer.hs
+ spaceleak/Example.hs view
@@ -0,0 +1,96 @@+module Main where++import Control.Monad.Exception.Asynchronous+   (Exceptional(Exceptional), force, pure, throwMonoid, broken, result, exception, )+import Control.Monad (mplus, )+import Data.Monoid (Monoid, mappend, mempty, )+++convert :: [Either String a] -> Exceptional String [a]+convert =+   emconcat .+   map (force . either throwMonoid (pure . (:[])))++emconcat :: Monoid a => [Exceptional e a] -> Exceptional e a+emconcat =+   force .+   foldr+      (\(Exceptional e a) ~(Exceptional es as) ->+          Exceptional (mplus e es) (mappend a as))+      (pure mempty)++econcat :: [Exceptional e a] -> Exceptional e [a]+econcat =+   force .+   foldr+      (\(Exceptional e a) ~(Exceptional es as) ->+          Exceptional (mplus e es) (a:as))+      (pure [])++convert0 :: [Either String a] -> Exceptional String [a]+convert0 =+   force .+   -- not quite mconcat, because we need lazy matching on the right operand+   foldr+      (\a b -> mappend a (force b))+      (pure []) .+   map (either throwMonoid (pure . (:[])))++convert1 :: [Either String a] -> Exceptional String [a]+convert1 =+   force .+   foldr+      (\ea -> force .+         either (mappend . throwMonoid) (\entry -> fmap (entry:)) ea)+      (pure [])++-- the String argument prevents caching and thus a space-leak+infinite :: String -> [Either String Integer]+infinite msg =+   map Right (iterate (1+) 0) ++ [Left msg]++-- the String argument prevents caching and thus a space-leak+infiniteExc :: String -> [Exceptional String Integer]+infiniteExc msg =+   map (Exceptional Nothing) (iterate (1+) 0) ++ [broken msg 0]++skip :: [a] -> [a]+skip = map head . iterate (drop 1000)++spaceLeak0 :: IO ()+spaceLeak0 =+   let r  = convert $ infinite "bla"+       e  = exception r+       xs = result r+   in  do mapM_ print $ skip xs+          print e++spaceLeak1 :: IO ()+spaceLeak1 =+   let Exceptional e xs = convert $ infinite "bla"+   in  do mapM_ print $ skip xs+          print e++spaceLeak2 :: IO ()+spaceLeak2 =+   let Exceptional e xs = econcat $ infiniteExc "bla"+   in  do mapM_ print $ skip xs+          print e++noSpaceLeak0 :: IO ()+noSpaceLeak0 =+   let r  = convert $ infinite "bla"+       _e = exception r+       xs = result r+   in  mapM_ print $ skip xs++noSpaceLeak1 :: IO ()+noSpaceLeak1 =+   let Exceptional _e xs = convert $ infinite "bla"+   in  mapM_ print $ skip xs++{-+ee-test +RTS -M32m -c30 -RTS+-}+main :: IO ()+main = spaceLeak2
+ spaceleak/Tar.hs view
@@ -0,0 +1,73 @@+module Main where++import qualified Codec.Archive.Tar as Tar+import qualified Codec.Archive.Tar.Entry as TarEntry+import Control.Monad.Exception.Asynchronous+   (Exceptional(Exceptional), force, pure, throwMonoid, result, exception, )+import qualified Data.ByteString.Lazy as B+++convert :: Tar.Entries -> Exceptional String [Tar.Entry]+convert =+   force .+   Tar.foldEntries+      (\entry -> fmap (entry:))+      (pure [])+      throwMonoid++-- the String argument prevents caching and thus a space-leak+infinite :: String -> Tar.Entries+infinite name =+   let tar =+          Tar.Next+             (TarEntry.directoryEntry $ either error id $+              TarEntry.toTarPath True name)+             tar+   in  tar++test :: String+test =+   map (const 'a') $ result $ convert $ infinite "test"++spaceLeak0 :: IO ()+spaceLeak0 =+   let r  = convert $ infinite "bla"+       e  = exception r+       xs = result r+   in  do mapM_ print [ "dir" | Tar.NormalFile _ _ <- map Tar.entryContent xs ]+          print e++spaceLeak1 :: IO ()+spaceLeak1 =+   let Exceptional e xs = convert $ infinite "bla"+   in  do mapM_ print [ "dir" | Tar.NormalFile _ _ <- map Tar.entryContent xs ]+          print e++{-+tar c /data1/ | ghc +RTS -M32m -c30 -RTS -e spaceLeak src/Tar.hs++tar c /data1/ | ./dist/build/ee-tar/ee-tar +RTS -M32m -c30 -RTS+-}+spaceLeak :: IO ()+spaceLeak = do+   tar <- B.getContents+   let a  = convert (Tar.read tar)+--       e  = exception a+       xs = result a+   print [ B.length bs | Tar.NormalFile bs _ <- map Tar.entryContent xs ]+--   print e++tarFold :: IO ()+tarFold = do+   tar <- B.getContents+   Tar.foldEntries+      (\x rest ->+          case Tar.entryContent x of+             Tar.NormalFile bs _ -> print (B.length bs) >> rest+             _ -> rest)+      (return ())+      print+      (Tar.read tar)++main :: IO ()+main = spaceLeak1
+ spaceleak/Unzip.hs view
@@ -0,0 +1,34 @@+{- |+This module implements something+that is very similar to our asynchronous exception approach.+However, it does not expose a memory leak. Why?+-}+module Main where+++unzipPattern :: [(a,b)] -> ([a], [b])+unzipPattern =+   foldr+      (\(a,b) ~(as,bs) -> (a:as, b:bs))+      ([], [])++unzipSelector :: [(a,b)] -> ([a], [b])+unzipSelector =+   foldr+      (\(a,b) asbs -> (a : fst asbs, b : snd asbs))+      ([], [])+++noSpaceLeak :: IO ()+noSpaceLeak =+   let xs = repeat ('a', 42::Int)+       (ys,zs) = unzipSelector xs+   in  do mapM_ putChar ys+          print $ last zs+++{-+ee-unzip +RTS -M1m -c30 -RTS+-}+main :: IO ()+main = noSpaceLeak
+ spaceleak/Writer.hs view
@@ -0,0 +1,29 @@+{- |+This module implements something+that is very similar to our asynchronous exception approach.+However, it does not expose a memory leak. Why?+-}+module Main where++import qualified Control.Monad.Trans.Writer as W+import qualified Data.Monoid as Mn+++noSpaceLeak0 :: IO ()+noSpaceLeak0 =+   let (xs,m) = W.runWriter $ sequence $ repeat $ return 'a'+   in  do mapM_ putChar xs+          print $ (m :: Mn.Last Int)++noSpaceLeak1 :: IO ()+noSpaceLeak1 =+   let p = W.runWriter $ sequence $ repeat $ return 'a'+   in  do mapM_ putChar (fst p)+          print $ (snd p :: Mn.Last Int)+++{-+ee-writer +RTS -M1m -c30 -RTS+-}+main :: IO ()+main = noSpaceLeak1
src/Control/Monad/Exception/Asynchronous.hs view
@@ -222,6 +222,7 @@   {- | construct Exceptional constructor lazily -}+{-# INLINE force #-} force :: Exceptional e a -> Exceptional e a force ~(Exceptional e a) = Exceptional e a 
src/Control/Monad/Exception/Label.hs view
@@ -15,7 +15,7 @@  import Control.Monad (liftM, ) import Control.Monad.Fix (MonadFix, )-import Control.Monad.Trans (MonadTrans, lift, )+import Control.Monad.Trans.Class (MonadTrans, lift, )   data LabeledException l e =
src/Control/Monad/Exception/Synchronous.hs view
@@ -60,7 +60,7 @@ import Control.Applicative (Applicative(pure, (<*>))) import Control.Monad (liftM, {- MonadPlus(mzero, mplus), -}) import Control.Monad.Fix (MonadFix, mfix, )-import Control.Monad.Trans (MonadTrans, lift, {- MonadIO(liftIO), -} )+import Control.Monad.Trans.Class (MonadTrans, lift, ) import Control.Monad.Trans.Error (ErrorT(ErrorT, runErrorT)) import Data.Monoid(Monoid, mappend, mempty, Endo(Endo, appEndo), ) 
src/Control/Monad/Label.hs view
@@ -18,7 +18,8 @@  import Control.Monad (MonadPlus, ap, ) import Control.Monad.Fix (MonadFix)-import Control.Monad.Trans (MonadTrans, MonadIO)+import Control.Monad.IO.Class (MonadIO, )+import Control.Monad.Trans.Class (MonadTrans, ) import qualified Control.Monad.Trans.Reader as Reader import Control.Monad.Trans.Reader (Reader, ReaderT(ReaderT), runReader, runReaderT, ) import Control.Monad.Instances ()
src/System/IO/Straight.hs view
@@ -18,7 +18,7 @@ import qualified Control.Monad.Exception.Synchronous as SyncExc import Control.Exception (IOException) import System.IO.Error (try)-import Control.Monad.Trans (MonadIO, liftIO, )+import Control.Monad.IO.Class (MonadIO, liftIO, )  import System.IO.Unsafe (unsafeInterleaveIO, ) @@ -45,11 +45,12 @@  -- helper classes for defining the MonadIO instance of SIO -{--It's important that no-one else can define instances of MonadSIO-because we cannot assert absence of exceptions in other monads.-It is also important not to export 'toSIO',-since we can also not assert absence of exceptions in IO actions.+{- |+Users of the library may define new instances of MonadSIO,+but monads other than SIO may not make the absence of exceptions explicit.+It is important however, that we do not make the method 'toSIO' public,+since this would allow users+the unsafe conversion from @IO@ to @SIO@. -} class Monad m => MonadSIO m where toSIO :: IO a -> m a instance MonadSIO SIO where toSIO = SIO