acquire-0.3.2: library/Acquire.hs
module Acquire where
import Acquire.Prelude
-- * IO
-------------------------
-- |
-- Execute an action, which uses a resource,
-- having a resource provider.
acquireAndUse :: Acquire env -> Use env err res -> IO (Either err res)
acquireAndUse (Acquire acquireIo) (Use useRdr) =
bracket acquireIo snd (runExceptT . runReaderT useRdr . fst)
-- * Acquire
-------------------------
-- |
-- Resource provider.
-- Abstracts over resource acquisition and releasing.
--
-- Composes well, allowing you to merge multiple providers into one.
--
-- Implementation of http://www.haskellforall.com/2013/06/the-resource-applicative.html
newtype Acquire env
= Acquire (IO (env, IO ()))
instance Functor Acquire where
fmap f (Acquire io) =
Acquire $ do
(env, release) <- io
return (f env, release)
instance Applicative Acquire where
pure env =
Acquire (pure (env, pure ()))
Acquire io1 <*> Acquire io2 =
Acquire $ do
(f, release1) <- io1
(x, release2) <- onException io2 release1
return (f x, release2 >> release1)
instance Monad Acquire where
return = pure
(>>=) (Acquire io1) k2 =
Acquire $ do
(resource1, release1) <- io1
(resource2, release2) <- case k2 resource1 of Acquire io2 -> onException io2 release1
return (resource2, release2 >> release1)
instance MonadIO Acquire where
liftIO io =
Acquire (fmap (,return ()) io)
-- * Use
-------------------------
-- |
-- Resource handler, which has a notion of pure errors.
newtype Use env err res = Use (ReaderT env (ExceptT err IO) res)
deriving (Functor, Applicative, Alternative, Monad, MonadPlus, MonadIO, MonadError err)
instance Bifunctor (Use env) where
first = mapErr
second = fmap
-- |
-- Map the environment of a resource handler.
mapEnv :: (b -> a) -> Use a err res -> Use b err res
mapEnv fn (Use rdr) = Use (withReaderT fn rdr)
-- |
-- Map the error of a resource handler.
mapErr :: (a -> b) -> Use env a res -> Use env b res
mapErr fn (Use rdr) = Use (mapReaderT (withExceptT fn) rdr)
-- |
-- Map both the environment and the error of a resource handler.
mapEnvAndErr :: (envB -> envA) -> (errA -> errB) -> Use envA errA res -> Use envB errB res
mapEnvAndErr envProj errProj (Use rdr) = Use (withReaderT envProj (mapReaderT (withExceptT errProj) rdr))