packages feed

managed (empty) → 1.0.0

raw patch · 5 files changed

+277/−0 lines, 5 filesdep +basedep +transformerssetup-changed

Dependencies added: base, transformers

Files

+ LICENSE view
@@ -0,0 +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.
+ Setup.hs view
@@ -0,0 +1,2 @@+import Distribution.Simple+main = defaultMain
+ managed.cabal view
@@ -0,0 +1,40 @@+Name: managed+Version: 1.0.0+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
+ src/Control/Monad/Managed.hs view
@@ -0,0 +1,178 @@+{-# 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) -> IOr ) -> [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,+    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++-- | 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
@@ -0,0 +1,33 @@+{-# 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,+    runManaged,++    -- * Re-exports+    -- $reexports+    module Control.Monad.IO.Class+    ) where++import Control.Monad.IO.Class (MonadIO(liftIO))+import Control.Monad.Managed (Managed, managed, runManaged)++{- $reexports+    "Control.Monad.IO.Class" re-exports 'MonadIO'+-}