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 :: forall env err res.
Acquire env -> Use env err res -> IO (Either err res)
acquireAndUse (Acquire IO (env, IO ())
acquireIo) (Use ReaderT env (ExceptT err IO) res
useRdr) =
  forall a b c. IO a -> (a -> IO b) -> (a -> IO c) -> IO c
bracket IO (env, IO ())
acquireIo forall a b. (a, b) -> b
snd (forall e (m :: * -> *) a. ExceptT e m a -> m (Either e a)
runExceptT forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. forall r (m :: * -> *) a. ReaderT r m a -> r -> m a
runReaderT ReaderT env (ExceptT err IO) res
useRdr forall {k} (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
Category cat =>
cat b c -> cat a b -> cat a c
. forall a b. (a, b) -> a
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 :: forall a b. (a -> b) -> Acquire a -> Acquire b
fmap a -> b
f (Acquire IO (a, IO ())
io) =
    forall env. IO (env, IO ()) -> Acquire env
Acquire forall a b. (a -> b) -> a -> b
$ do
      (a
env, IO ()
release) <- IO (a, IO ())
io
      forall (m :: * -> *) a. Monad m => a -> m a
return (a -> b
f a
env, IO ()
release)

instance Applicative Acquire where
  pure :: forall a. a -> Acquire a
pure a
env =
    forall env. IO (env, IO ()) -> Acquire env
Acquire (forall (f :: * -> *) a. Applicative f => a -> f a
pure (a
env, forall (f :: * -> *) a. Applicative f => a -> f a
pure ()))
  Acquire IO (a -> b, IO ())
io1 <*> :: forall a b. Acquire (a -> b) -> Acquire a -> Acquire b
<*> Acquire IO (a, IO ())
io2 =
    forall env. IO (env, IO ()) -> Acquire env
Acquire forall a b. (a -> b) -> a -> b
$ do
      (a -> b
f, IO ()
release1) <- IO (a -> b, IO ())
io1
      (a
x, IO ()
release2) <- forall a b. IO a -> IO b -> IO a
onException IO (a, IO ())
io2 IO ()
release1
      forall (m :: * -> *) a. Monad m => a -> m a
return (a -> b
f a
x, IO ()
release2 forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> IO ()
release1)

instance Monad Acquire where
  return :: forall a. a -> Acquire a
return = forall (f :: * -> *) a. Applicative f => a -> f a
pure
  >>= :: forall a b. Acquire a -> (a -> Acquire b) -> Acquire b
(>>=) (Acquire IO (a, IO ())
io1) a -> Acquire b
k2 =
    forall env. IO (env, IO ()) -> Acquire env
Acquire forall a b. (a -> b) -> a -> b
$ do
      (a
resource1, IO ()
release1) <- IO (a, IO ())
io1
      (b
resource2, IO ()
release2) <- case a -> Acquire b
k2 a
resource1 of Acquire IO (b, IO ())
io2 -> forall a b. IO a -> IO b -> IO a
onException IO (b, IO ())
io2 IO ()
release1
      forall (m :: * -> *) a. Monad m => a -> m a
return (b
resource2, IO ()
release2 forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> IO ()
release1)

instance MonadIO Acquire where
  liftIO :: forall a. IO a -> Acquire a
liftIO IO a
io =
    forall env. IO (env, IO ()) -> Acquire env
Acquire (forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap (,forall (m :: * -> *) a. Monad m => a -> m a
return ()) IO a
io)

-- * Use

-------------------------

-- |
-- Resource handler, which has a notion of pure errors.
newtype Use env err res = Use (ReaderT env (ExceptT err IO) res)
  deriving (forall a b. a -> Use env err b -> Use env err a
forall a b. (a -> b) -> Use env err a -> Use env err b
forall env err a b. a -> Use env err b -> Use env err a
forall env err a b. (a -> b) -> Use env err a -> Use env err b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
<$ :: forall a b. a -> Use env err b -> Use env err a
$c<$ :: forall env err a b. a -> Use env err b -> Use env err a
fmap :: forall a b. (a -> b) -> Use env err a -> Use env err b
$cfmap :: forall env err a b. (a -> b) -> Use env err a -> Use env err b
Functor, forall a. a -> Use env err a
forall env err. Functor (Use env err)
forall a b. Use env err a -> Use env err b -> Use env err a
forall a b. Use env err a -> Use env err b -> Use env err b
forall a b. Use env err (a -> b) -> Use env err a -> Use env err b
forall env err a. a -> Use env err a
forall a b c.
(a -> b -> c) -> Use env err a -> Use env err b -> Use env err c
forall env err a b. Use env err a -> Use env err b -> Use env err a
forall env err a b. Use env err a -> Use env err b -> Use env err b
forall env err a b.
Use env err (a -> b) -> Use env err a -> Use env err b
forall env err a b c.
(a -> b -> c) -> Use env err a -> Use env err b -> Use env err c
forall (f :: * -> *).
Functor f
-> (forall a. a -> f a)
-> (forall a b. f (a -> b) -> f a -> f b)
-> (forall a b c. (a -> b -> c) -> f a -> f b -> f c)
-> (forall a b. f a -> f b -> f b)
-> (forall a b. f a -> f b -> f a)
-> Applicative f
<* :: forall a b. Use env err a -> Use env err b -> Use env err a
$c<* :: forall env err a b. Use env err a -> Use env err b -> Use env err a
*> :: forall a b. Use env err a -> Use env err b -> Use env err b
$c*> :: forall env err a b. Use env err a -> Use env err b -> Use env err b
liftA2 :: forall a b c.
(a -> b -> c) -> Use env err a -> Use env err b -> Use env err c
$cliftA2 :: forall env err a b c.
(a -> b -> c) -> Use env err a -> Use env err b -> Use env err c
<*> :: forall a b. Use env err (a -> b) -> Use env err a -> Use env err b
$c<*> :: forall env err a b.
Use env err (a -> b) -> Use env err a -> Use env err b
pure :: forall a. a -> Use env err a
$cpure :: forall env err a. a -> Use env err a
Applicative, forall a. Use env err a
forall a. Use env err a -> Use env err [a]
forall a. Use env err a -> Use env err a -> Use env err a
forall {env} {err}. Monoid err => Applicative (Use env err)
forall env err a. Monoid err => Use env err a
forall env err a. Monoid err => Use env err a -> Use env err [a]
forall env err a.
Monoid err =>
Use env err a -> Use env err a -> Use env err a
forall (f :: * -> *).
Applicative f
-> (forall a. f a)
-> (forall a. f a -> f a -> f a)
-> (forall a. f a -> f [a])
-> (forall a. f a -> f [a])
-> Alternative f
many :: forall a. Use env err a -> Use env err [a]
$cmany :: forall env err a. Monoid err => Use env err a -> Use env err [a]
some :: forall a. Use env err a -> Use env err [a]
$csome :: forall env err a. Monoid err => Use env err a -> Use env err [a]
<|> :: forall a. Use env err a -> Use env err a -> Use env err a
$c<|> :: forall env err a.
Monoid err =>
Use env err a -> Use env err a -> Use env err a
empty :: forall a. Use env err a
$cempty :: forall env err a. Monoid err => Use env err a
Alternative, forall a. a -> Use env err a
forall env err. Applicative (Use env err)
forall a b. Use env err a -> Use env err b -> Use env err b
forall a b. Use env err a -> (a -> Use env err b) -> Use env err b
forall env err a. a -> Use env err a
forall env err a b. Use env err a -> Use env err b -> Use env err b
forall env err a b.
Use env err a -> (a -> Use env err b) -> Use env err b
forall (m :: * -> *).
Applicative m
-> (forall a b. m a -> (a -> m b) -> m b)
-> (forall a b. m a -> m b -> m b)
-> (forall a. a -> m a)
-> Monad m
return :: forall a. a -> Use env err a
$creturn :: forall env err a. a -> Use env err a
>> :: forall a b. Use env err a -> Use env err b -> Use env err b
$c>> :: forall env err a b. Use env err a -> Use env err b -> Use env err b
>>= :: forall a b. Use env err a -> (a -> Use env err b) -> Use env err b
$c>>= :: forall env err a b.
Use env err a -> (a -> Use env err b) -> Use env err b
Monad, forall a. Use env err a
forall a. Use env err a -> Use env err a -> Use env err a
forall {env} {err}. Monoid err => Monad (Use env err)
forall env err. Monoid err => Alternative (Use env err)
forall env err a. Monoid err => Use env err a
forall env err a.
Monoid err =>
Use env err a -> Use env err a -> Use env err a
forall (m :: * -> *).
Alternative m
-> Monad m
-> (forall a. m a)
-> (forall a. m a -> m a -> m a)
-> MonadPlus m
mplus :: forall a. Use env err a -> Use env err a -> Use env err a
$cmplus :: forall env err a.
Monoid err =>
Use env err a -> Use env err a -> Use env err a
mzero :: forall a. Use env err a
$cmzero :: forall env err a. Monoid err => Use env err a
MonadPlus, forall a. IO a -> Use env err a
forall env err. Monad (Use env err)
forall env err a. IO a -> Use env err a
forall (m :: * -> *).
Monad m -> (forall a. IO a -> m a) -> MonadIO m
liftIO :: forall a. IO a -> Use env err a
$cliftIO :: forall env err a. IO a -> Use env err a
MonadIO, MonadError err)

instance Bifunctor (Use env) where
  first :: forall a b c. (a -> b) -> Use env a c -> Use env b c
first = forall a b env res. (a -> b) -> Use env a res -> Use env b res
mapErr
  second :: forall b c a. (b -> c) -> Use env a b -> Use env a c
second = forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap

-- |
-- Map the environment of a resource handler.
mapEnv :: (b -> a) -> Use a err res -> Use b err res
mapEnv :: forall b a err res. (b -> a) -> Use a err res -> Use b err res
mapEnv b -> a
fn (Use ReaderT a (ExceptT err IO) res
rdr) = forall env err res.
ReaderT env (ExceptT err IO) res -> Use env err res
Use (forall r' r (m :: * -> *) a.
(r' -> r) -> ReaderT r m a -> ReaderT r' m a
withReaderT b -> a
fn ReaderT a (ExceptT err IO) res
rdr)

-- |
-- Map the error of a resource handler.
mapErr :: (a -> b) -> Use env a res -> Use env b res
mapErr :: forall a b env res. (a -> b) -> Use env a res -> Use env b res
mapErr a -> b
fn (Use ReaderT env (ExceptT a IO) res
rdr) = forall env err res.
ReaderT env (ExceptT err IO) res -> Use env err res
Use (forall (m :: * -> *) a (n :: * -> *) b r.
(m a -> n b) -> ReaderT r m a -> ReaderT r n b
mapReaderT (forall (m :: * -> *) e e' a.
Functor m =>
(e -> e') -> ExceptT e m a -> ExceptT e' m a
withExceptT a -> b
fn) ReaderT env (ExceptT a IO) res
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 :: forall envB envA errA errB res.
(envB -> envA)
-> (errA -> errB) -> Use envA errA res -> Use envB errB res
mapEnvAndErr envB -> envA
envProj errA -> errB
errProj (Use ReaderT envA (ExceptT errA IO) res
rdr) = forall env err res.
ReaderT env (ExceptT err IO) res -> Use env err res
Use (forall r' r (m :: * -> *) a.
(r' -> r) -> ReaderT r m a -> ReaderT r' m a
withReaderT envB -> envA
envProj (forall (m :: * -> *) a (n :: * -> *) b r.
(m a -> n b) -> ReaderT r m a -> ReaderT r n b
mapReaderT (forall (m :: * -> *) e e' a.
Functor m =>
(e -> e') -> ExceptT e m a -> ExceptT e' m a
withExceptT errA -> errB
errProj) ReaderT envA (ExceptT errA IO) res
rdr))