managed-1.0.10: A monad for managed values

Safe Haskell | Safe-Inferred
Language | Haskell2010

Control.Monad.Managed

Contents

- Managed
- Re-exports

Description

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 ()

`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 `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))

Synopsis

- data Managed a
- class MonadIO m => MonadManaged m where
  - using :: Managed a -> m a
- managed :: MonadManaged m => (forall r. (a -> IO r) -> IO r) -> m a
- managed_ :: MonadManaged m => (forall r. IO r -> IO r) -> m ()
- defer :: MonadManaged m => IO r -> m ()
- with :: Managed a -> (a -> IO r) -> IO r
- runManaged :: Managed () -> IO ()
- class Monad m => MonadIO (m :: Type -> Type) where
  - liftIO :: IO a -> m a

# Managed

data Managed a Source #

A managed resource that you acquire using `with`

#### Instances

Instances details

MonadFail Managed Source # |
Instance details Defined in Control.Monad.Managed Methods fail :: String -> Managed a Source #
MonadIO Managed Source # |
Instance details Defined in Control.Monad.Managed Methods liftIO :: IO a -> Managed a Source #
Applicative Managed Source # |
Instance details Defined in Control.Monad.Managed Methods pure :: a -> Managed a Source # (<*>) :: Managed (a -> b) -> Managed a -> Managed b Source # liftA2 :: (a -> b -> c) -> Managed a -> Managed b -> Managed c Source # (*>) :: Managed a -> Managed b -> Managed b Source # (<*) :: Managed a -> Managed b -> Managed a Source #
Functor Managed Source # |
Instance details Defined in Control.Monad.Managed Methods fmap :: (a -> b) -> Managed a -> Managed b Source # (<$) :: a -> Managed b -> Managed a Source #
Monad Managed Source # |
Instance details Defined in Control.Monad.Managed Methods (>>=) :: Managed a -> (a -> Managed b) -> Managed b Source # (>>) :: Managed a -> Managed b -> Managed b Source # return :: a -> Managed a Source #
MonadManaged Managed Source # |
Instance details Defined in Control.Monad.Managed Methods using :: Managed a -> Managed a Source #
Monoid a => Monoid (Managed a) Source # |
Instance details Defined in Control.Monad.Managed Methods mempty :: Managed a Source # mappend :: Managed a -> Managed a -> Managed a Source # mconcat :: [Managed a] -> Managed a Source #
Semigroup a => Semigroup (Managed a) Source # |
Instance details Defined in Control.Monad.Managed Methods (<>) :: Managed a -> Managed a -> Managed a Source # sconcat :: NonEmpty (Managed a) -> Managed a Source # stimes :: Integral b => b -> Managed a -> Managed a Source #
Floating a => Floating (Managed a) Source # |

Instance details

Defined in Control.Monad.Managed

Methods

pi :: Managed a Source #

exp :: Managed a -> Managed a Source #

log :: Managed a -> Managed a Source #

sqrt :: Managed a -> Managed a Source #

(**) :: Managed a -> Managed a -> Managed a Source #

logBase :: Managed a -> Managed a -> Managed a Source #

sin :: Managed a -> Managed a Source #

cos :: Managed a -> Managed a Source #

tan :: Managed a -> Managed a Source #

asin :: Managed a -> Managed a Source #

acos :: Managed a -> Managed a Source #

atan :: Managed a -> Managed a Source #

sinh :: Managed a -> Managed a Source #

cosh :: Managed a -> Managed a Source #

tanh :: Managed a -> Managed a Source #

asinh :: Managed a -> Managed a Source #

acosh :: Managed a -> Managed a Source #

atanh :: Managed a -> Managed a Source #

log1p :: Managed a -> Managed a Source #

expm1 :: Managed a -> Managed a Source #

log1pexp :: Managed a -> Managed a Source #

log1mexp :: Managed a -> Managed a Source #

Num a => Num (Managed a) Source # |
Instance details Defined in Control.Monad.Managed Methods (+) :: Managed a -> Managed a -> Managed a Source # (-) :: Managed a -> Managed a -> Managed a Source # (*) :: Managed a -> Managed a -> Managed a Source # negate :: Managed a -> Managed a Source # abs :: Managed a -> Managed a Source # signum :: Managed a -> Managed a Source # fromInteger :: Integer -> Managed a Source #
Fractional a => Fractional (Managed a) Source # |
Instance details Defined in Control.Monad.Managed Methods (/) :: Managed a -> Managed a -> Managed a Source # recip :: Managed a -> Managed a Source # fromRational :: Rational -> Managed a Source #

class MonadIO m => MonadManaged m where Source #

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)

Methods

using :: Managed a -> m a Source #

#### Instances

Instances details

MonadManaged Managed Source # |
Instance details Defined in Control.Monad.Managed Methods using :: Managed a -> Managed a Source #
MonadManaged m => MonadManaged (MaybeT m) Source # |
Instance details Defined in Control.Monad.Managed Methods using :: Managed a -> MaybeT m a Source #
MonadManaged m => MonadManaged (ExceptT e m) Source # |
Instance details Defined in Control.Monad.Managed Methods using :: Managed a -> ExceptT e m a Source #
MonadManaged m => MonadManaged (IdentityT m) Source # |
Instance details Defined in Control.Monad.Managed Methods using :: Managed a -> IdentityT m a Source #
MonadManaged m => MonadManaged (ReaderT r m) Source # |
Instance details Defined in Control.Monad.Managed Methods using :: Managed a -> ReaderT r m a Source #
MonadManaged m => MonadManaged (StateT s m) Source # |
Instance details Defined in Control.Monad.Managed Methods using :: Managed a -> StateT s m a Source #
MonadManaged m => MonadManaged (StateT s m) Source # |
Instance details Defined in Control.Monad.Managed Methods using :: Managed a -> StateT s m a Source #
(Monoid w, MonadManaged m) => MonadManaged (WriterT w m) Source # |
Instance details Defined in Control.Monad.Managed Methods using :: Managed a -> WriterT w m a Source #
(Monoid w, MonadManaged m) => MonadManaged (WriterT w m) Source # |
Instance details Defined in Control.Monad.Managed Methods using :: Managed a -> WriterT w m a Source #
MonadManaged m => MonadManaged (ContT r m) Source # |
Instance details Defined in Control.Monad.Managed Methods using :: Managed a -> ContT r m a Source #
(Monoid w, MonadManaged m) => MonadManaged (RWST r w s m) Source # |
Instance details Defined in Control.Monad.Managed Methods using :: Managed a -> RWST r w s m a Source #
(Monoid w, MonadManaged m) => MonadManaged (RWST r w s m) Source # |
Instance details Defined in Control.Monad.Managed Methods using :: Managed a -> RWST r w s m a Source #

managed :: MonadManaged m => (forall r. (a -> IO r) -> IO r) -> m a Source #

Build a `Managed` value

managed_ :: MonadManaged m => (forall r. IO r -> IO r) -> m () Source #

Like `managed` but for resource-less operations.

defer :: MonadManaged m => IO r -> m () Source #

Defer running an action until exit (via `runManaged`).

For example, the following code will print "Hello" followed by "Goodbye":

    runManaged $ do
      defer $ liftIO $ putStrLn "Goodbye"
      liftIO $ putStrLn "Hello"

with :: Managed a -> (a -> IO r) -> IO r Source #

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.

runManaged :: Managed () -> IO () Source #

Run a `Managed` computation, enforcing that no acquired resources leak

# Re-exports

Control.Monad.IO.Class re-exports `MonadIO`

class Monad m => MonadIO (m :: Type -> Type) where Source #

Monads in which `IO` computations may be embedded. Any monad built by applying a sequence of monad transformers to the `IO` monad will be an instance of this class.

Instances should satisfy the following laws, which state that `liftIO` is a transformer of monads:

-     liftIO . return = return

-     liftIO (m >>= f) = liftIO m >>= (liftIO . f)

Methods

liftIO :: IO a -> m a Source #

Lift a computation from the `IO` monad. This allows us to run IO computations in any monadic stack, so long as it supports these kinds of operations (i.e. `IO` is the base monad for the stack).

### Example

Expand

    import Control.Monad.Trans.State -- from the "transformers" library

    printState :: Show s => StateT s IO ()
    printState = do
      state <- get
      liftIO $ print state

Had we omitted ``liftIO``, we would have ended up with this error:

    • Couldn't match type ‘IO’ with ‘StateT s IO’
     Expected type: StateT s IO ()
       Actual type: IO ()

The important part here is the mismatch between `StateT s IO ()` and ``IO` ()`.

Luckily, we know of a function that takes an ``IO` a` and returns an `(m a)`: ``liftIO``, enabling us to run the program and see the expected results:

    > evalStateT printState "hello"
    "hello"

    > evalStateT printState 3
    3

#### Instances

Instances details

MonadIO IO | Since: base-4.9.0.0
Instance details Defined in Control.Monad.IO.Class Methods liftIO :: IO a -> IO a Source #
MonadIO Managed Source # |
Instance details Defined in Control.Monad.Managed Methods liftIO :: IO a -> Managed a Source #
MonadIO m => MonadIO (MaybeT m) |
Instance details Defined in Control.Monad.Trans.Maybe Methods liftIO :: IO a -> MaybeT m a Source #
MonadIO m => MonadIO (ExceptT e m) |
Instance details Defined in Control.Monad.Trans.Except Methods liftIO :: IO a -> ExceptT e m a Source #
MonadIO m => MonadIO (IdentityT m) |
Instance details Defined in Control.Monad.Trans.Identity Methods liftIO :: IO a -> IdentityT m a Source #
MonadIO m => MonadIO (ReaderT r m) |
Instance details Defined in Control.Monad.Trans.Reader Methods liftIO :: IO a -> ReaderT r m a Source #
MonadIO m => MonadIO (StateT s m) |
Instance details Defined in Control.Monad.Trans.State.Lazy Methods liftIO :: IO a -> StateT s m a Source #
MonadIO m => MonadIO (StateT s m) |
Instance details Defined in Control.Monad.Trans.State.Strict Methods liftIO :: IO a -> StateT s m a Source #
(Monoid w, MonadIO m) => MonadIO (WriterT w m) |
Instance details Defined in Control.Monad.Trans.Writer.Lazy Methods liftIO :: IO a -> WriterT w m a Source #
(Monoid w, MonadIO m) => MonadIO (WriterT w m) |
Instance details Defined in Control.Monad.Trans.Writer.Strict Methods liftIO :: IO a -> WriterT w m a Source #
MonadIO m => MonadIO (ContT r m) |
Instance details Defined in Control.Monad.Trans.Cont Methods liftIO :: IO a -> ContT r m a Source #
(Monoid w, MonadIO m) => MonadIO (RWST r w s m) |
Instance details Defined in Control.Monad.Trans.RWS.Lazy Methods liftIO :: IO a -> RWST r w s m a Source #
(Monoid w, MonadIO m) => MonadIO (RWST r w s m) |
Instance details Defined in Control.Monad.Trans.RWS.Strict Methods liftIO :: IO a -> RWST r w s m a Source #