managed 1.0.2 → 1.0.3
raw patch · 5 files changed
+364/−283 lines, 5 filesdep ~basedep ~transformerssetup-changedPVP ok
version bump matches the API change (PVP)
Dependency ranges changed: base, transformers
API changes (from Hackage documentation)
+ Control.Monad.Managed: class MonadIO m => MonadManaged m
+ Control.Monad.Managed: instance (GHC.Base.Monoid w, Control.Monad.Managed.MonadManaged m) => Control.Monad.Managed.MonadManaged (Control.Monad.Trans.RWS.Lazy.RWST r w s m)
+ Control.Monad.Managed: instance (GHC.Base.Monoid w, Control.Monad.Managed.MonadManaged m) => Control.Monad.Managed.MonadManaged (Control.Monad.Trans.RWS.Strict.RWST r w s m)
+ Control.Monad.Managed: instance (GHC.Base.Monoid w, Control.Monad.Managed.MonadManaged m) => Control.Monad.Managed.MonadManaged (Control.Monad.Trans.Writer.Lazy.WriterT w m)
+ Control.Monad.Managed: instance (GHC.Base.Monoid w, Control.Monad.Managed.MonadManaged m) => Control.Monad.Managed.MonadManaged (Control.Monad.Trans.Writer.Strict.WriterT w m)
+ Control.Monad.Managed: instance Control.Monad.Managed.MonadManaged Control.Monad.Managed.Managed
+ Control.Monad.Managed: instance Control.Monad.Managed.MonadManaged m => Control.Monad.Managed.MonadManaged (Control.Monad.Trans.Cont.ContT r m)
+ Control.Monad.Managed: instance Control.Monad.Managed.MonadManaged m => Control.Monad.Managed.MonadManaged (Control.Monad.Trans.Except.ExceptT e m)
+ Control.Monad.Managed: instance Control.Monad.Managed.MonadManaged m => Control.Monad.Managed.MonadManaged (Control.Monad.Trans.Identity.IdentityT m)
+ Control.Monad.Managed: instance Control.Monad.Managed.MonadManaged m => Control.Monad.Managed.MonadManaged (Control.Monad.Trans.Maybe.MaybeT m)
+ Control.Monad.Managed: instance Control.Monad.Managed.MonadManaged m => Control.Monad.Managed.MonadManaged (Control.Monad.Trans.Reader.ReaderT r m)
+ Control.Monad.Managed: instance Control.Monad.Managed.MonadManaged m => Control.Monad.Managed.MonadManaged (Control.Monad.Trans.State.Lazy.StateT s m)
+ Control.Monad.Managed: instance Control.Monad.Managed.MonadManaged m => Control.Monad.Managed.MonadManaged (Control.Monad.Trans.State.Strict.StateT s m)
+ Control.Monad.Managed: using :: MonadManaged m => Managed a -> m a
+ Control.Monad.Managed.Safe: class MonadIO m => MonadManaged m
+ Control.Monad.Managed.Safe: using :: MonadManaged m => Managed a -> m a
Files
- LICENSE +24/−24
- Setup.hs +2/−2
- managed.cabal +40/−40
- src/Control/Monad/Managed.hs +262/−183
- src/Control/Monad/Managed/Safe.hs +36/−34
LICENSE view
@@ -1,24 +1,24 @@-Copyright (c) 2014 Gabriel Gonzalez -All rights reserved. - -Redistribution and use in source and binary forms, with or without modification, -are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright notice, - this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - * Neither the name of Gabriel Gonzalez nor the names of other contributors - may be used to endorse or promote products derived from this software - without specific prior written permission. - -THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND -ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED -WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE -DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR -ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES -(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; -LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON -ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +Copyright (c) 2014 Gabriel Gonzalez+All rights reserved.++Redistribution and use in source and binary forms, with or without modification,+are permitted provided that the following conditions are met:+ * Redistributions of source code must retain the above copyright notice,+ this list of conditions and the following disclaimer.+ * Redistributions in binary form must reproduce the above copyright notice,+ this list of conditions and the following disclaimer in the documentation+ and/or other materials provided with the distribution.+ * Neither the name of Gabriel Gonzalez nor the names of other contributors+ may be used to endorse or promote products derived from this software+ without specific prior written permission.++THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED+WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR+ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES+(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON+ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Setup.hs view
@@ -1,2 +1,2 @@-import Distribution.Simple -main = defaultMain +import Distribution.Simple+main = defaultMain
managed.cabal view
@@ -1,40 +1,40 @@-Name: managed -Version: 1.0.2 -Cabal-Version: >=1.8.0.2 -Build-Type: Simple -License: BSD3 -License-File: LICENSE -Copyright: 2014 Gabriel Gonzalez -Author: Gabriel Gonzalez -Maintainer: Gabriel439@gmail.com -Bug-Reports: https://github.com/Gabriel439/Haskell-Managed-Library/issues -Synopsis: A monad for managed values -Description: In Haskell you very often acquire values using the @with...@ - idiom using functions of type @(a -> IO r) -> IO r@. This idiom forms a - @Monad@, which is a special case of the @ContT@ monad (from @transformers@) or - the @Codensity@ monad (from @kan-extensions@). The main purpose behind this - package is to provide a restricted form of these monads specialized to this - unusually common case. - . - The reason this package defines a specialized version of these types is to: - . - * be more beginner-friendly, - . - * simplify inferred types and error messages, and: - . - * provide some additional type class instances that would otherwise be orphan - instances -Category: Control -Source-Repository head - Type: git - Location: https://github.com/Gabriel439/Haskell-Managed-Library - -Library - Hs-Source-Dirs: src - Build-Depends: - base >= 4.5 && < 5 , - transformers >= 0.2.0.0 && < 0.5 - Exposed-Modules: - Control.Monad.Managed, - Control.Monad.Managed.Safe - GHC-Options: -O2 -Wall +Name: managed+Version: 1.0.3+Cabal-Version: >=1.8.0.2+Build-Type: Simple+License: BSD3+License-File: LICENSE+Copyright: 2014 Gabriel Gonzalez+Author: Gabriel Gonzalez+Maintainer: Gabriel439@gmail.com+Bug-Reports: https://github.com/Gabriel439/Haskell-Managed-Library/issues+Synopsis: A monad for managed values+Description: In Haskell you very often acquire values using the @with...@+ idiom using functions of type @(a -> IO r) -> IO r@. This idiom forms a+ @Monad@, which is a special case of the @ContT@ monad (from @transformers@) or+ the @Codensity@ monad (from @kan-extensions@). The main purpose behind this+ package is to provide a restricted form of these monads specialized to this+ unusually common case.+ .+ The reason this package defines a specialized version of these types is to:+ .+ * be more beginner-friendly,+ .+ * simplify inferred types and error messages, and:+ .+ * provide some additional type class instances that would otherwise be orphan+ instances+Category: Control+Source-Repository head+ Type: git+ Location: https://github.com/Gabriel439/Haskell-Managed-Library++Library+ Hs-Source-Dirs: src+ Build-Depends:+ base >= 4.5 && < 5 ,+ transformers >= 0.2.0.0 && < 0.6+ Exposed-Modules:+ Control.Monad.Managed,+ Control.Monad.Managed.Safe+ GHC-Options: -O2 -Wall
src/Control/Monad/Managed.hs view
@@ -1,183 +1,262 @@-{-# LANGUAGE RankNTypes #-} - -{-| An example Haskell program to copy data from one handle to another might - look like this: - -> main = -> withFile "inFile.txt" ReadMode $ \inHandle -> -> withFile "outFile.txt" WriteMode $ \outHandle -> -> copy inHandle outHandle -> -> -- A hypothetical function that copies data from one handle to another -> copy :: Handle -> Handle -> IO () - - `System.IO.withFile` is one of many functions that acquire some resource in - an exception-safe way. These functions take a callback function as an - argument and they invoke the callback on the resource when it becomes - available, guaranteeing that the resource is properly disposed if the - callback throws an exception. - - These functions usually have a type that ends with the following pattern: - -> Callback -> -- ----------- -> withXXX :: ... -> (a -> IO r) -> IO r - - Here are some examples of this pattern from the @base@ libraries: - -> withArray :: Storable a => [a] -> (Ptr a -> IO r) -> IO r -> withBuffer :: Buffer e -> (Ptr e -> IO r) -> IO r -> withCAString :: String -> (CString -> IO r) -> IO r -> withForeignPtr :: ForeignPtr a -> (Ptr a -> IO r) -> IO r -> withMVar :: Mvar a -> (a -> IO r) -> IO r -> withPool :: (Pool -> IO r) -> IO r - - Acquiring multiple resources in this way requires nesting callbacks. - However, you can wrap anything of the form @((a -> IO r) -> IO r)@ in the - `Managed` monad, which translates binds to callbacks for you: - -> import Control.Monad.Managed -> import System.IO -> -> inFile :: FilePath -> Managed Handle -> inFile filePath = managed (withFile filePath ReadMode) -> -> outFile :: FilePath -> Managed Handle -> outFile filePath = managed (withFile filePath WriteMode) -> -> main = runManaged $ do -> inHandle <- inFile "inFile.txt" -> outHandle <- outFile "outFile.txt" -> liftIO (copy inHandle outHandle) - - ... or you can just wrap things inline: - -> main = runManaged $ do -> inHandle <- managed (withFile "inFile.txt" ReadMode) -> outHandle <- managed (withFile "outFile.txt" WriteMode) -> liftIO (copy inHandle outHandle) - - Additionally, since `Managed` is a `Monad`, you can take advantage of all - your favorite combinators from "Control.Monad". For example, the - `Foreign.Marshal.Utils.withMany` function from "Foreign.Marshal.Utils" - becomes a trivial wrapper around `mapM`: - -> withMany :: (a -> (b -> IO r) -> IO r) -> [a] -> ([b] -> IO r) -> IO r -> withMany f = with . mapM (Managed . f) - - Another reason to use `Managed` is that if you wrap a `Monoid` value in - `Managed` you get back a new `Monoid`: - -> instance Monoid a => Monoid (Managed a) - - This lets you combine managed resources transparently. You can also lift - operations from some numeric type classes this way, too, such as the `Num` - type class. --} - -module Control.Monad.Managed ( - -- * Managed - Managed, - managed, - managed_, - with, - runManaged, - - -- * Re-exports - -- $reexports - module Control.Monad.IO.Class - ) where - -import Control.Applicative (Applicative(pure, (<*>)), liftA2) -import Control.Monad.IO.Class (MonadIO(liftIO)) -import Data.Monoid (Monoid(mempty, mappend)) - --- | A managed resource that you acquire using `with` -newtype Managed a = Managed { (>>-) :: forall r . (a -> IO r) -> IO r } - -instance Functor Managed where - fmap f mx = Managed (\return_ -> - mx >>- \x -> - return_ (f x) ) - -instance Applicative Managed where - pure r = Managed (\return_ -> - return_ r ) - - mf <*> mx = Managed (\return_ -> - mf >>- \f -> - mx >>- \x -> - return_ (f x) ) - -instance Monad Managed where - return r = Managed (\return_ -> - return_ r ) - - ma >>= f = Managed (\return_ -> - ma >>- \a -> - f a >>- \b -> - return_ b ) - -instance MonadIO Managed where - liftIO m = Managed (\return_ -> do - a <- m - return_ a ) - -instance Monoid a => Monoid (Managed a) where - mempty = pure mempty - - mappend = liftA2 mappend - -instance Num a => Num (Managed a) where - fromInteger = pure . fromInteger - negate = fmap negate - abs = fmap abs - signum = fmap signum - (+) = liftA2 (+) - (*) = liftA2 (*) - (-) = liftA2 (-) - -instance Fractional a => Fractional (Managed a) where - fromRational = pure . fromRational - recip = fmap recip - (/) = liftA2 (/) - -instance Floating a => Floating (Managed a) where - pi = pure pi - exp = fmap exp - sqrt = fmap sqrt - log = fmap log - sin = fmap sin - tan = fmap tan - cos = fmap cos - asin = fmap sin - atan = fmap atan - acos = fmap acos - sinh = fmap sinh - tanh = fmap tanh - cosh = fmap cosh - asinh = fmap asinh - atanh = fmap atanh - acosh = fmap acosh - (**) = liftA2 (**) - logBase = liftA2 logBase - --- | Build a `Managed` value -managed :: (forall r . (a -> IO r) -> IO r) -> Managed a -managed = Managed - --- | Like 'managed' but for resource-less operations. -managed_ :: (forall r. IO r -> IO r) -> Managed () -managed_ f = managed $ \g -> f $ g () - --- | Acquire a `Managed` value -with :: Managed a -> (a -> IO r) -> IO r -with = (>>-) - --- | Run a `Managed` computation, enforcing that no acquired resources leak -runManaged :: Managed () -> IO () -runManaged m = m >>- return - -{- $reexports - "Control.Monad.IO.Class" re-exports 'MonadIO' --} +{-# LANGUAGE RankNTypes #-}++{-| An example Haskell program to copy data from one handle to another might+ look like this:++> main =+> withFile "inFile.txt" ReadMode $ \inHandle ->+> withFile "outFile.txt" WriteMode $ \outHandle ->+> copy inHandle outHandle+>+> -- A hypothetical function that copies data from one handle to another+> copy :: Handle -> Handle -> IO ()++ `System.IO.withFile` is one of many functions that acquire some resource in+ an exception-safe way. These functions take a callback function as an+ argument and they invoke the callback on the resource when it becomes+ available, guaranteeing that the resource is properly disposed if the+ callback throws an exception.++ These functions usually have a type that ends with the following pattern:++> Callback+> -- -----------+> withXXX :: ... -> (a -> IO r) -> IO r++ Here are some examples of this pattern from the @base@ libraries:++> withArray :: Storable a => [a] -> (Ptr a -> IO r) -> IO r+> withBuffer :: Buffer e -> (Ptr e -> IO r) -> IO r+> withCAString :: String -> (CString -> IO r) -> IO r+> withForeignPtr :: ForeignPtr a -> (Ptr a -> IO r) -> IO r+> withMVar :: Mvar a -> (a -> IO r) -> IO r+> withPool :: (Pool -> IO r) -> IO r++ Acquiring multiple resources in this way requires nesting callbacks.+ However, you can wrap anything of the form @((a -> IO r) -> IO r)@ in the+ `Managed` monad, which translates binds to callbacks for you:++> import Control.Monad.Managed+> import System.IO+>+> inFile :: FilePath -> Managed Handle+> inFile filePath = managed (withFile filePath ReadMode)+>+> outFile :: FilePath -> Managed Handle+> outFile filePath = managed (withFile filePath WriteMode)+>+> main = runManaged $ do+> inHandle <- inFile "inFile.txt"+> outHandle <- outFile "outFile.txt"+> liftIO (copy inHandle outHandle)++ ... or you can just wrap things inline:++> main = runManaged $ do+> inHandle <- managed (withFile "inFile.txt" ReadMode)+> outHandle <- managed (withFile "outFile.txt" WriteMode)+> liftIO (copy inHandle outHandle)++ Additionally, since `Managed` is a `Monad`, you can take advantage of all+ your favorite combinators from "Control.Monad". For example, the+ `Foreign.Marshal.Utils.withMany` function from "Foreign.Marshal.Utils"+ becomes a trivial wrapper around `mapM`:++> withMany :: (a -> (b -> IO r) -> IO r) -> [a] -> ([b] -> IO r) -> IO r+> withMany f = with . mapM (Managed . f)++ Another reason to use `Managed` is that if you wrap a `Monoid` value in+ `Managed` you get back a new `Monoid`:++> instance Monoid a => Monoid (Managed a)++ This lets you combine managed resources transparently. You can also lift+ operations from some numeric type classes this way, too, such as the `Num`+ type class.++ NOTE: `Managed` may leak space if used in an infinite loop like this+ example:++> import Control.Monad+> import Control.Monad.Managed+> +> main = runManaged (forever (liftIO (print 1)))++ If you need to acquire a resource for a long-lived loop, you can instead+ acquire the resource first and run the loop in `IO`, using either of the+ following two equivalent idioms:++> with resource (\r -> forever (useThe r))+>+> do r <- resource+> liftIO (forever (useThe r))+-}++module Control.Monad.Managed (+ -- * Managed+ Managed,+ MonadManaged(..),+ managed,+ managed_,+ with,+ runManaged,++ -- * Re-exports+ -- $reexports+ module Control.Monad.IO.Class+ ) where++import Control.Applicative (Applicative(pure, (<*>)), liftA2)+import Control.Monad.IO.Class (MonadIO(liftIO))+import Control.Monad.Trans.Class (lift)+import Data.Monoid (Monoid(mempty, mappend))++import qualified Control.Monad.Trans.Cont as Cont+import qualified Control.Monad.Trans.Except as Except+import qualified Control.Monad.Trans.Identity as Identity+import qualified Control.Monad.Trans.Maybe as Maybe+import qualified Control.Monad.Trans.Reader as Reader+import qualified Control.Monad.Trans.RWS.Lazy as RWS.Lazy+import qualified Control.Monad.Trans.RWS.Strict as RWS.Strict+import qualified Control.Monad.Trans.State.Lazy as State.Lazy+import qualified Control.Monad.Trans.State.Strict as State.Strict+import qualified Control.Monad.Trans.Writer.Lazy as Writer.Lazy+import qualified Control.Monad.Trans.Writer.Strict as Writer.Strict++-- | A managed resource that you acquire using `with`+newtype Managed a = Managed { (>>-) :: forall r . (a -> IO r) -> IO r }++instance Functor Managed where+ fmap f mx = Managed (\return_ ->+ mx >>- \x ->+ return_ (f x) )++instance Applicative Managed where+ pure r = Managed (\return_ ->+ return_ r )++ mf <*> mx = Managed (\return_ ->+ mf >>- \f ->+ mx >>- \x ->+ return_ (f x) )++instance Monad Managed where+ return r = Managed (\return_ ->+ return_ r )++ ma >>= f = Managed (\return_ ->+ ma >>- \a ->+ f a >>- \b ->+ return_ b )++instance MonadIO Managed where+ liftIO m = Managed (\return_ -> do+ a <- m+ return_ a )++instance Monoid a => Monoid (Managed a) where+ mempty = pure mempty++ mappend = liftA2 mappend++instance Num a => Num (Managed a) where+ fromInteger = pure . fromInteger+ negate = fmap negate+ abs = fmap abs+ signum = fmap signum+ (+) = liftA2 (+)+ (*) = liftA2 (*)+ (-) = liftA2 (-)++instance Fractional a => Fractional (Managed a) where+ fromRational = pure . fromRational+ recip = fmap recip+ (/) = liftA2 (/)++instance Floating a => Floating (Managed a) where+ pi = pure pi+ exp = fmap exp+ sqrt = fmap sqrt+ log = fmap log+ sin = fmap sin+ tan = fmap tan+ cos = fmap cos+ asin = fmap sin+ atan = fmap atan+ acos = fmap acos+ sinh = fmap sinh+ tanh = fmap tanh+ cosh = fmap cosh+ asinh = fmap asinh+ atanh = fmap atanh+ acosh = fmap acosh+ (**) = liftA2 (**)+ logBase = liftA2 logBase++{-| You can embed a `Managed` action within any `Monad` that implements+ `MonadManaged` by using the `using` function++ All instances must obey the following two laws:++> using (return x) = return x+>+> using (m >>= f) = using m >>= \x -> using (f x)+-}+class MonadIO m => MonadManaged m where+ using :: Managed a -> m a++instance MonadManaged Managed where+ using = id++instance MonadManaged m => MonadManaged (Cont.ContT r m) where+ using m = lift (using m)++instance MonadManaged m => MonadManaged (Except.ExceptT e m) where+ using m = lift (using m)++instance MonadManaged m => MonadManaged (Identity.IdentityT m) where+ using m = lift (using m)++instance MonadManaged m => MonadManaged (Maybe.MaybeT m) where+ using m = lift (using m)++instance MonadManaged m => MonadManaged (Reader.ReaderT r m) where+ using m = lift (using m)++instance (Monoid w, MonadManaged m) => MonadManaged (RWS.Lazy.RWST r w s m) where+ using m = lift (using m)++instance (Monoid w, MonadManaged m) => MonadManaged (RWS.Strict.RWST r w s m) where+ using m = lift (using m)++instance MonadManaged m => MonadManaged (State.Strict.StateT s m) where+ using m = lift (using m)++instance MonadManaged m => MonadManaged (State.Lazy.StateT s m) where+ using m = lift (using m)++instance (Monoid w, MonadManaged m) => MonadManaged (Writer.Strict.WriterT w m) where+ using m = lift (using m)++instance (Monoid w, MonadManaged m) => MonadManaged (Writer.Lazy.WriterT w m) where+ using m = lift (using m)++-- | Build a `Managed` value+managed :: (forall r . (a -> IO r) -> IO r) -> Managed a+managed = Managed++-- | Like 'managed' but for resource-less operations.+managed_ :: (forall r. IO r -> IO r) -> Managed ()+managed_ f = managed $ \g -> f $ g ()++-- | Acquire a `Managed` value+with :: Managed a -> (a -> IO r) -> IO r+with = (>>-)++-- | Run a `Managed` computation, enforcing that no acquired resources leak+runManaged :: Managed () -> IO ()+runManaged m = m >>- return++{- $reexports+ "Control.Monad.IO.Class" re-exports 'MonadIO'+-}
src/Control/Monad/Managed/Safe.hs view
@@ -1,34 +1,36 @@-{-# LANGUAGE RankNTypes #-} - -{-| This module is a safer subset of "Control.Monad.Managed" that only lets you - unwrap the `Managed` type using `runManaged`. This enforces that you never - leak acquired resources from a `Managed` computation. - - In general, you should strive to propagate the `Managed` type as much as - possible and use `runManaged` when you are done with acquired resources. - However, there are legitimate circumstances where you want to return a value - other than acquired resource from the bracketed computation, which requires - using `Control.Monad.Managed.with`. - - This module is not the default because you can also use the `Managed` type - for callback-based code that is completely unrelated to resources. --} - -module Control.Monad.Managed.Safe ( - -- * Managed - Managed, - managed, - managed_, - runManaged, - - -- * Re-exports - -- $reexports - module Control.Monad.IO.Class - ) where - -import Control.Monad.IO.Class (MonadIO(liftIO)) -import Control.Monad.Managed (Managed, managed, managed_, runManaged) - -{- $reexports - "Control.Monad.IO.Class" re-exports 'MonadIO' --} +{-# LANGUAGE RankNTypes #-}++{-| This module is a safer subset of "Control.Monad.Managed" that only lets you+ unwrap the `Managed` type using `runManaged`. This enforces that you never+ leak acquired resources from a `Managed` computation.++ In general, you should strive to propagate the `Managed` type as much as+ possible and use `runManaged` when you are done with acquired resources.+ However, there are legitimate circumstances where you want to return a value+ other than acquired resource from the bracketed computation, which requires+ using `Control.Monad.Managed.with`.++ This module is not the default because you can also use the `Managed` type+ for callback-based code that is completely unrelated to resources.+-}++module Control.Monad.Managed.Safe (+ -- * Managed+ Managed,+ MonadManaged(..),+ managed,+ managed_,+ runManaged,++ -- * Re-exports+ -- $reexports+ module Control.Monad.IO.Class+ ) where++import Control.Monad.IO.Class (MonadIO(liftIO))+import Control.Monad.Managed+ (Managed, MonadManaged(..), managed, managed_, runManaged)++{- $reexports+ "Control.Monad.IO.Class" re-exports 'MonadIO'+-}