pipes-safe 1.1.0 → 1.2.0
raw patch · 3 files changed
+41/−41 lines, 3 filesdep ~pipesPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: pipes
API changes (from Hackage documentation)
Files
- Control/Proxy/Safe/Core.hs +22/−21
- Control/Proxy/Safe/Tutorial.hs +17/−18
- pipes-safe.cabal +2/−2
Control/Proxy/Safe/Core.hs view
@@ -1,6 +1,6 @@ -- | Exception handling and resource management integrated with proxies -{-# LANGUAGE Rank2Types, CPP, KindSignatures #-}+{-# LANGUAGE Rank2Types, CPP #-} module Control.Proxy.Safe.Core ( -- * Exception Handling@@ -22,7 +22,6 @@ -- * Checked Exceptions -- $check CheckP(..),- tryK, tryIO, -- * Finalization@@ -36,7 +35,11 @@ -- $prompt unsafeCloseU, unsafeCloseD,- unsafeClose+ unsafeClose,++ -- * Deprecated+ -- $deprecated+ tryK ) where import qualified Control.Exception as Ex@@ -48,10 +51,9 @@ import qualified Control.Proxy.Core.Fast as PF import qualified Control.Proxy.Core.Correct as PC import Control.Proxy ((->>), (>>~))-import Control.Proxy.Trans.Maybe (MaybeP(runMaybeP)) import qualified Control.Proxy.Trans.Either as E-import qualified Control.Proxy.Trans.Reader as R import Control.Proxy.Trans.Either hiding (throw, catch, handle)+import qualified Control.Proxy.Trans.Reader as R import Data.IORef (IORef, newIORef, readIORef, writeIORef) #if MIN_VERSION_base(4,6,0) #else@@ -64,8 +66,7 @@ transformer. The 'ExceptionP' type synonym simplifies type signatures. Use 'runEitherP' / 'runEitherK' from the re-exported- @Control.Proxy.Trans.Either@ to convert 'ExceptionP' back to the base- monad+ @Control.Proxy.Trans.Either@ to convert 'ExceptionP' back to the base monad. This module does not re-export 'E.throw', 'E.catch', and 'E.handle' from @Control.Proxy.Trans.Either@ and instead defines new versions similar to the@@ -203,7 +204,6 @@ hd <- readIORef hdRef hd ) - {- I don't export 'register' only because people rarely want to guard solely against premature termination. Usually they also want to guard against exceptions, too.@@ -237,7 +237,9 @@ -> p a' a b' b m r -> p a' a b' b m r register morph h k =- (P.runIdentityK (P.hoistK morph up) ->> k) >>~ P.runIdentityK (P.hoistK morph dn)+ P.runIdentityP . P.hoist morph . up+ ->> k+ >>~ P.runIdentityP . P.hoist morph . dn where dn b0 = do huRef <- lift $ SafeIO $ asks downstream@@ -316,20 +318,9 @@ instance (CheckP p) => CheckP (R.ReaderP i p) where try p = EitherP $ R.ReaderP $ \i -> runEitherP $ try (R.unReaderP p i) --- | Check all exceptions for a 'P.Proxy' \'@K@\'leisli arrow-tryK- :: (CheckP p)- => (q -> p a' a b' b IO r) -> (q -> ExceptionP p a' a b' b SafeIO r)-tryK = (try .)- {-| Check all exceptions for an 'IO' action - 'tryIO' is a monad morphism:--> tryIO $ do x <- m = do x <- tryIO m-> f x tryIO (f x)->-> tryIO (return x) = return x -- Not true for asynchronous exceptions+ 'tryIO' is a monad morphism, with the same caveat as 'try'. -} tryIO :: (P.Proxy p) => IO r -> ExceptionP p a' a b' b SafeIO r tryIO io = EitherP $ P.runIdentityP $ lift $ SafeIO $ ReaderT $ \s ->@@ -549,3 +540,13 @@ -} unsafeClose :: (P.Proxy p) => r -> ExceptionP p a' a b' b SafeIO r unsafeClose = unsafeCloseU P.>=> unsafeCloseD++{- $deprecated+ To be removed in version @2.0.0@+-}++tryK+ :: (CheckP p)+ => (q -> p a' a b' b IO r) -> (q -> ExceptionP p a' a b' b SafeIO r)+tryK = (try .)+{-# DEPRECATED tryK "Use '(try .)' instead" #-}
Control/Proxy/Safe/Tutorial.hs view
@@ -87,17 +87,15 @@ > lift $ print a Do we need to rewrite it to use resource management abstractions? Not at- all! We can use 'try' / 'tryK' to automatically promote any \"unmanaged\"- proxy to a \"managed\" proxy:+ all! We can use 'try' to automatically promote any \"unmanaged\" proxy to a+ \"managed\" proxy: -> tryK-> :: (CheckP p)-> => (q -> p a' a b' b IO r) -> q -> ExceptionP p a' a b' b SafeIO r +> try :: (CheckP p) => p a' a b' b IO r -> ExceptionP p a' a b' b SafeIO r >-> tryK printer :: (CheckP p, Show a) => () -> Consumer (Exception p) a SafeIO r+> try . printer :: (CheckP p, Show a) => () -> Consumer (Exception p) a SafeIO r > > session :: (CheckP p) => () -> Session (Exception p) SafeIO ()-> session = readFileS "test.txt" >-> tryK printer+> session = readFileS "test.txt" >-> try . printer The 'CheckP' constraint indicates that the base 'Proxy' type must be promotable using 'try'.@@ -123,7 +121,7 @@ finalize the handle: > main = runSafeIO $ runProxy $ runEitherK $-> readFileS "test.txt" >-> takeB_ 2 >-> tryK printD+> readFileS "test.txt" >-> takeB_ 2 >-> try . printD >>> main {File Open}@@ -141,7 +139,7 @@ > threadDelay 1000 > killThread tID > runSafeIO $ runProxy $ runEitherK $-> foreverK (readFileS "test.txt") >-> tryK printD+> foreverK (readFileS "test.txt") >-> try . printD >>> main ...@@ -181,7 +179,7 @@ These let you embed native exception handling into proxies. For example, we could use exception handling to recover from a file opening error: -> import Prelude hiding (catch) -- if using base <= 4.5+> import Prelude hiding (catch) -- if using `base <= 4.5` > > openFileS :: (CheckP p) => () -> Producer (ExceptionP p) String SafeIO () > openFileS () = (do@@ -192,7 +190,7 @@ > tryIO $ print (e :: IOException) > openFileS () ) ->>> runSafeIO $ runProxy $ runEitherK $ openFileS >-> tryK printD+>>> runSafeIO $ runProxy $ runEitherK $ openFileS >-> try . printD Select a file: oops oops: openFile: does not exist (No such file or directory)@@ -221,7 +219,7 @@ > threadDelay 5000000 -- Every 5 seconds > killThread tid > trySafeIO $ runProxy $ runEitherK $-> heartbeat . (openFileS >-> tryK printD)+> heartbeat . (openFileS >-> try . printD) >>> main Select a file:@@ -254,7 +252,7 @@ > threadDelay 1000 > killThread tID > trySafeIO $ runProxy $ runEitherK $-> foreverK (readFileS "test.txt") >-> tryK printD+> foreverK (readFileS "test.txt") >-> try . printD >>> main ...@@ -283,7 +281,7 @@ For example, consider the following 'Session': > session () = do-> (readFileS "test.hs" >-> takeB_ 2 >-> tryK printD) ()+> (readFileS "test.hs" >-> takeB_ 2 >-> try . printD) () > tryIO $ putStrLn "Look busy" >>> runSafeIO $ runProxy $ runEitherK session@@ -302,7 +300,7 @@ own hands and manually finalize things even more promptly: > session () = do-> (readFileS "test.hs" >-> (takeB_ 2 >=> unsafeClose) >-> tryK printD) ()+> (readFileS "test.hs" >-> (takeB_ 2 >=> unsafeClose) >-> try . printD) () > tryIO $ putStrLn "Look busy" >>> runSafeIO $ runProxy $ runEitherK session@@ -351,7 +349,7 @@ documentation in the @Control.Proxy.Morph@ module (from the @pipes@ package) lists the full set of laws. The important laws you should remember are: -> tryK (f >-> g) = tryK f >-> tryK g+> try . (f >-> g) = try . f >-> try . g > try (request a') = request a' @@ -414,9 +412,10 @@ > hClose h ) > (\h -> p h b') - ... and now we can 'readFileS' in terms of 'withFileS' and 'hGetLineS':+ ... and now we can define 'readFileS' in terms of 'withFileS' and+ 'hGetLineS': -> readFileS file = withFileS file (\h -> tryK (hGetLineS h))+> readFileS file = withFileS file (\h -> try . (hGetLineS h)) If 'hGetLineS' throws an error within its own code, 'withFileS' will still properly finalize the handle. This works in spite of 'hGetLineS' never
pipes-safe.cabal view
@@ -1,5 +1,5 @@ Name: pipes-safe-Version: 1.1.0+Version: 1.2.0 Cabal-Version: >=1.8.0.2 Build-Type: Simple License: BSD3@@ -37,7 +37,7 @@ Build-Depends: base >= 4 && < 5 , transformers >= 0.2.0.0 && < 0.4,- pipes >= 3.2.0 && < 3.3+ pipes >= 3.2.0 && < 3.4 Exposed-Modules: Control.Proxy.Safe, Control.Proxy.Safe.Core,