pipes-safe 2.0.0 → 2.0.1
raw patch · 3 files changed
+53/−27 lines, 3 files
Files
- pipes-safe.cabal +1/−1
- src/Pipes/Safe.hs +45/−18
- src/Pipes/Safe/Prelude.hs +7/−8
pipes-safe.cabal view
@@ -1,5 +1,5 @@ Name: pipes-safe-Version: 2.0.0+Version: 2.0.1 Cabal-Version: >=1.8.0.2 Build-Type: Simple License: BSD3
src/Pipes/Safe.hs view
@@ -67,8 +67,10 @@ -- * MonadSafe , ReleaseKey- , Base , MonadSafe(..)++ -- * Utilities+ -- $utilities , onException , finally , bracket@@ -240,26 +242,15 @@ -- | Token used to 'release' a previously 'register'ed finalizer newtype ReleaseKey = ReleaseKey { unlock :: Integer } --- | The monad used to run resource management actions, typically 'IO'-type family Base (m :: * -> *) :: * -> *--type instance Base IO = IO-type instance Base (SafeT m) = m-type instance Base (Proxy a' a b' b m) = Base m-type instance Base (I.IdentityT m) = Base m-type instance Base (E.CatchT m) = Base m-type instance Base (R.ReaderT i m) = Base m-type instance Base (S.StateT s m) = Base m-type instance Base (S'.StateT s m) = Base m-type instance Base (W.WriterT w m) = Base m-type instance Base (W'.WriterT w m) = Base m-type instance Base (RWS.RWST i w s m) = Base m-type instance Base (RWS'.RWST i w s m) = Base m- {-| 'MonadSafe' lets you 'register' and 'release' finalizers that execute in a 'Base' monad -}-class (MonadCatch m, MonadIO m, Monad (Base m)) => MonadSafe m where+class (MonadCatch m, MonadIO m, MonadIO (Base m)) => MonadSafe m where+ {-| The monad used to run resource management actions, corresponding to the+ monad directly beneath 'SafeT'+ -}+ type Base (m :: * -> *) :: * -> *+ -- | Lift an action from the 'Base' monad liftBase :: Base m r -> m r @@ -277,6 +268,8 @@ release :: ReleaseKey -> m () instance (MonadIO m, MonadCatch m) => MonadSafe (SafeT m) where+ type Base (SafeT m) = m+ liftBase = lift register io = do@@ -293,51 +286,61 @@ writeIORef ioref $! Finalizers n (M.delete (unlock key) fs) instance (MonadSafe m) => MonadSafe (Proxy a' a b' b m) where+ type Base (Proxy a' a b' b m) = Base m liftBase = lift . liftBase register = lift . register release = lift . release instance (MonadSafe m) => MonadSafe (I.IdentityT m) where+ type Base (I.IdentityT m) = Base m liftBase = lift . liftBase register = lift . register release = lift . release instance (MonadSafe m) => MonadSafe (E.CatchT m) where+ type Base (E.CatchT m) = Base m liftBase = lift . liftBase register = lift . register release = lift . release instance (MonadSafe m) => MonadSafe (R.ReaderT i m) where+ type Base (R.ReaderT i m) = Base m liftBase = lift . liftBase register = lift . register release = lift . release instance (MonadSafe m) => MonadSafe (S.StateT s m) where+ type Base (S.StateT s m) = Base m liftBase = lift . liftBase register = lift . register release = lift . release instance (MonadSafe m) => MonadSafe (S'.StateT s m) where+ type Base (S'.StateT s m) = Base m liftBase = lift . liftBase register = lift . register release = lift . release instance (MonadSafe m, Monoid w) => MonadSafe (W.WriterT w m) where+ type Base (W.WriterT w m) = Base m liftBase = lift . liftBase register = lift . register release = lift . release instance (MonadSafe m, Monoid w) => MonadSafe (W'.WriterT w m) where+ type Base (W'.WriterT w m) = Base m liftBase = lift . liftBase register = lift . register release = lift . release instance (MonadSafe m, Monoid w) => MonadSafe (RWS.RWST i w s m) where+ type Base (RWS.RWST i w s m) = Base m liftBase = lift . liftBase register = lift . register release = lift . release instance (MonadSafe m, Monoid w) => MonadSafe (RWS'.RWST i w s m) where+ type Base (RWS'.RWST i w s m) = Base m liftBase = lift . liftBase register = lift . register release = lift . release@@ -354,6 +357,30 @@ release key return r {-# INLINABLE onException #-}++{- $utilities+ These utilities let you supply a finalizer that runs in the 'Base' monad+ (i.e. the monad directly beneath 'SafeT'). If you don't need to use the+ full power of the 'Base' monad and you only need to use to use 'IO', then+ just wrap the finalizer in 'liftIO', like this:++> myAction `finally` (liftIO myFinalizer)++ This will lead to a simple inferred type with a single 'MonadSafe'+ constraint:++> (MonadSafe m) => ...++ For examples of this, see the utilities in "Pipes.Safe.Prelude".++ If you omit the 'liftIO', the compiler will infer the following constraint+ instead:++> (MonadSafe m, Base m ~ IO) => ...++ This means that this function would require 'IO' directly beneath the+ 'SafeT' monad transformer, which might not be what you want.+-} {-| Analogous to 'C.finally' from @Control.Monad.Catch@, except this also protects against premature termination
src/Pipes/Safe/Prelude.hs view
@@ -1,6 +1,6 @@ -- | Simple resource management functions -{-# LANGUAGE RankNTypes, TypeFamilies #-}+{-# LANGUAGE RankNTypes #-} module Pipes.Safe.Prelude ( -- * Handle management@@ -12,17 +12,16 @@ writeFile ) where +import Control.Monad.IO.Class (MonadIO(liftIO)) import Pipes (Producer', Consumer')-import Pipes.Safe (bracket, MonadSafe, Base)+import Pipes.Safe (bracket, MonadSafe) import qualified Pipes.Prelude as P import qualified System.IO as IO import Prelude hiding (readFile, writeFile) -- | Acquire a 'IO.Handle' within 'MonadSafe'-withFile- :: (MonadSafe m, Base m ~ IO)- => FilePath -> IO.IOMode -> (IO.Handle -> m r) -> m r-withFile file ioMode = bracket (IO.openFile file ioMode) IO.hClose+withFile :: (MonadSafe m) => FilePath -> IO.IOMode -> (IO.Handle -> m r) -> m r+withFile file ioMode = bracket (liftIO $ IO.openFile file ioMode) (liftIO . IO.hClose) {-# INLINABLE withFile #-} {- $strings@@ -35,13 +34,13 @@ {-| Read lines from a file, automatically opening and closing the file as necessary -}-readFile :: (MonadSafe m, Base m ~ IO) => FilePath -> Producer' String m ()+readFile :: (MonadSafe m) => FilePath -> Producer' String m () readFile file = withFile file IO.ReadMode P.fromHandle {-# INLINABLE readFile #-} {-| Write lines to a file, automatically opening and closing the file as necessary -}-writeFile :: (MonadSafe m, Base m ~ IO) => FilePath -> Consumer' String m r+writeFile :: (MonadSafe m) => FilePath -> Consumer' String m r writeFile file = withFile file IO.WriteMode P.toHandle {-# INLINABLE writeFile #-}