managed-1.0.7/0000755000000000000000000000000013611737027011310 5ustar0000000000000000managed-1.0.7/Setup.hs0000644000000000000000000000005613611737027012745 0ustar0000000000000000import Distribution.Simple main = defaultMain managed-1.0.7/LICENSE0000644000000000000000000000275713611737027012330 0ustar0000000000000000Copyright (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. managed-1.0.7/managed.cabal0000644000000000000000000000277713611737027013705 0ustar0000000000000000Name: managed Version: 1.0.7 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 Tested-With: GHC == 7.6.3, GHC == 7.8.4, GHC == 7.10.2, GHC == 8.0.1 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 if !impl(ghc >= 8.0) Build-Depends: semigroups >= 0.16 && < 0.19 Exposed-Modules: Control.Monad.Managed, Control.Monad.Managed.Safe GHC-Options: -Wall managed-1.0.7/src/0000755000000000000000000000000013611737027012077 5ustar0000000000000000managed-1.0.7/src/Control/0000755000000000000000000000000013611737027013517 5ustar0000000000000000managed-1.0.7/src/Control/Monad/0000755000000000000000000000000013611737027014555 5ustar0000000000000000managed-1.0.7/src/Control/Monad/Managed.hs0000644000000000000000000002271513611737027016454 0ustar0000000000000000{-# LANGUAGE CPP #-} {-# 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.Monad.IO.Class (MonadIO(liftIO)) #if MIN_VERSION_base(4,9,0) import Control.Monad.Fail as MonadFail (MonadFail(..)) #endif import Control.Monad.Trans.Class (lift) #if MIN_VERSION_base(4,8,0) import Control.Applicative (liftA2) #else import Control.Applicative import Data.Monoid (Monoid(..)) #endif #if !(MIN_VERSION_base(4,11,0)) import Data.Semigroup (Semigroup(..)) #endif import qualified Control.Monad.Trans.Cont as Cont #if MIN_VERSION_transformers(0,4,0) import qualified Control.Monad.Trans.Except as Except #endif 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 ) #if MIN_VERSION_base(4,9,0) instance MonadFail Managed where fail s = Managed (\return_ -> do a <- MonadFail.fail s return_ a ) #endif instance Semigroup a => Semigroup (Managed a) where (<>) = liftA2 (<>) instance Monoid a => Monoid (Managed a) where mempty = pure mempty #if !(MIN_VERSION_base(4,11,0)) mappend = liftA2 mappend #endif 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) #if MIN_VERSION_transformers(0,4,0) instance MonadManaged m => MonadManaged (Except.ExceptT e m) where using m = lift (using m) #endif 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 This is a potentially unsafe function since it allows a resource to escape its scope. For example, you might use `Managed` to safely acquire a file handle, like this: > import qualified System.IO as IO > > example :: Managed Handle > example = managed (IO.withFile "foo.txt" IO.ReadMode) ... and if you never used the `with` function then you would never run the risk of accessing the `Handle` after the file was closed. However, if you use `with` then you can incorrectly access the handle after the handle is closed, like this: > bad :: IO () > bad = do > handle <- with example return > IO.hPutStrLn handle "bar" -- This will fail because the handle is closed ... so only use `with` if you know what you are doing and you're returning a value that is not a resource being managed. -} 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' -} managed-1.0.7/src/Control/Monad/Managed/0000755000000000000000000000000013611737027016111 5ustar0000000000000000managed-1.0.7/src/Control/Monad/Managed/Safe.hs0000644000000000000000000000223713611737027017327 0ustar0000000000000000{-# 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' -}