managed 1.0.1 → 1.0.2
raw patch · 5 files changed
+283/−283 lines, 5 filessetup-changedPVP: major bump suggested
API removals or changes: PVP suggests a major version bump
API changes (from Hackage documentation)
- Control.Monad.Managed: instance Applicative Managed
- Control.Monad.Managed: instance Floating a => Floating (Managed a)
- Control.Monad.Managed: instance Fractional a => Fractional (Managed a)
- Control.Monad.Managed: instance Functor Managed
- Control.Monad.Managed: instance Monad Managed
- Control.Monad.Managed: instance MonadIO Managed
- Control.Monad.Managed: instance Monoid a => Monoid (Managed a)
- Control.Monad.Managed: instance Num a => Num (Managed a)
+ Control.Monad.Managed: instance Control.Monad.IO.Class.MonadIO Control.Monad.Managed.Managed
+ Control.Monad.Managed: instance GHC.Base.Applicative Control.Monad.Managed.Managed
+ Control.Monad.Managed: instance GHC.Base.Functor Control.Monad.Managed.Managed
+ Control.Monad.Managed: instance GHC.Base.Monad Control.Monad.Managed.Managed
+ Control.Monad.Managed: instance GHC.Base.Monoid a => GHC.Base.Monoid (Control.Monad.Managed.Managed a)
+ Control.Monad.Managed: instance GHC.Float.Floating a => GHC.Float.Floating (Control.Monad.Managed.Managed a)
+ Control.Monad.Managed: instance GHC.Num.Num a => GHC.Num.Num (Control.Monad.Managed.Managed a)
+ Control.Monad.Managed: instance GHC.Real.Fractional a => GHC.Real.Fractional (Control.Monad.Managed.Managed a)
Files
- LICENSE +24/−24
- Setup.hs +2/−2
- managed.cabal +40/−40
- src/Control/Monad/Managed.hs +183/−183
- src/Control/Monad/Managed/Safe.hs +34/−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.1-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 ,- 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.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
src/Control/Monad/Managed.hs view
@@ -1,183 +1,183 @@-{-# 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. +-} + +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' +-}
src/Control/Monad/Managed/Safe.hs view
@@ -1,34 +1,34 @@-{-# 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, + 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' +-}