{-# LANGUAGE DerivingVia #-}
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
{-# LANGUAGE InstanceSigs #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE UnicodeSyntax #-}

{- |
Description : Lexically-scoped exception-safe resource usage
Copyright   : Copyright 2022 Shea Levy.
License     : Apache-2.0
Maintainer  : shea@shealevy.com

This module defines interfaces for safe resource usage on top of 'GeneralAllocate',
where resource cleanup happens at the end of a lexical scope.

For contexts where nested scope-based allocation and release is insufficient, see
"Control.Monad.Allocate".
-}
module Control.Monad.With where

import Control.Exception.Safe
import Control.Monad.Reader
import Control.Monad.ST
import Control.Monad.Trans.Resource.Internal
import Data.Functor.Identity
import Data.GeneralAllocate
import Data.Void

{- | A monad allowing for exception-safe resource usage within a lexical scope.

The guarantees of 'MonadWith' are weaker than t'Control.Monad.Catch.MonadMask': in some
monads, it's possible for resources not to get cleaned up if the /entire/ monadic
computation is going to be aborted (e.g. an async exception sent to a thread executing a monad
with no exception catching). Of course, t'Control.Monad.Catch.MonadMask' itself can't guarantee
cleanup in the presence of @SIGKILL@... In any case, this allows for 'MonadWith' to be implemented
lawfully in more monads (see 'WithNoContinuation'). In particular, the 'MonadWith' instances for
'IO', 'ST', and 'Identity' allow for writing monad-generic exception-safe code which can be properly
instantiated in 'IO' or mocked out in 'ST'/'Identity' without changing the code.
-}
class Monad m  MonadWith m where
  -- | Data characterizing exceptional exit from the scope.
  type WithException m

  type WithException m = SomeException

  -- | Allocate, use, and release a resource in some scope, threading through some state.
  --
  -- If resource acquisition succeeds, the resource is guaranteed to be released
  -- /if the monadic computation itself is going to continue/. This is weaker than
  -- the guarantees of v'Control.Monad.Catch.generalBracket', which can't be
  -- implemented in monads without exception catching.
  --
  -- See 'generalWith' for the common use case where state threading isn't needed.
  stateThreadingGeneralWith
     GeneralAllocate m (WithException m) releaseReturn b a
    -- ^ Allocate the resource
     (a  m b)
    -- ^ Use the resource
     m (b, releaseReturn)

{- | Describe the allocation and release of a resource.

A specialization of 'GeneralAllocate' for the most
common case with 'MonadWith', see 'generalWith'.
-}
type With m = GeneralAllocate m (WithException m) ()

{- | Allocate, use, and release a resource in some scope.

If resource acquisition succeeds, the resource is guaranteed to be released
/if the monadic computation itself is going to continue/. This is weaker than
the guarantees of v'Control.Monad.Catch.generalBracket', which can't be
implemented in monads without exception catching.
-}
generalWith
   (MonadWith m)
   With m b a
  -- ^ Allocate the resource
   (a  m b)
  -- ^ Use the resource
   m b
generalWith :: forall (m :: * -> *) b a.
MonadWith m =>
With m b a -> (a -> m b) -> m b
generalWith With m b a
alloc = (forall a b. (a, b) -> a
fst forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$>) forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) releaseReturn b a.
MonadWith m =>
GeneralAllocate m (WithException m) releaseReturn b a
-> (a -> m b) -> m (b, releaseReturn)
stateThreadingGeneralWith With m b a
alloc

{- | Run some action if the first action fails.

Exception propagation will continue after the failure action runs.

If failure occurs, the failure action is guaranteed to run
/if the monadic compuation itself is going to continue/. This is
weaker than the guranatess of v'Control.Monad.Catch.onError', which can't
be implemented in monads without exception catching.
-}
onFailure
   (MonadWith m)
   m a
  -- ^ Main action
   (WithException m  m b)
  -- ^ Failure action
   m a
onFailure :: forall (m :: * -> *) a b.
MonadWith m =>
m a -> (WithException m -> m b) -> m a
onFailure m a
go WithException m -> m b
err = forall (m :: * -> *) b a.
MonadWith m =>
With m b a -> (a -> m b) -> m b
generalWith GeneralAllocate m (WithException m) () a ()
alloc (forall a b. a -> b -> a
const m a
go)
 where
  alloc :: GeneralAllocate m (WithException m) () a ()
alloc = forall (m :: * -> *) e releaseReturn releaseArg a.
((forall x. m x -> m x)
 -> m (GeneralAllocated m e releaseReturn releaseArg a))
-> GeneralAllocate m e releaseReturn releaseArg a
GeneralAllocate forall a b. (a -> b) -> a -> b
$ \forall x. m x -> m x
_  forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) e releaseReturn releaseArg a.
a
-> (GeneralReleaseType e releaseArg -> m releaseReturn)
-> GeneralAllocated m e releaseReturn releaseArg a
GeneralAllocated () GeneralReleaseType (WithException m) a -> m ()
rel
  rel :: GeneralReleaseType (WithException m) a -> m ()
rel (ReleaseFailure WithException m
e) = WithException m -> m b
err WithException m
e forall (m :: * -> *) a b. Monad m => m a -> m b -> m b
>> forall (f :: * -> *) a. Applicative f => a -> f a
pure ()
  rel GeneralReleaseType (WithException m) a
_ = forall (f :: * -> *) a. Applicative f => a -> f a
pure ()

{- | Run some action after another one completes in an exception-safe manner.

The final action is guaranteed to run
/if the monadic compuation itself is going to continue/. This is
weaker than the guranatess of v'Control.Monad.Catch.finally', which can't
be implemented in monads without exception catching.
-}
generalFinally
   (MonadWith m)
   m a
  -- ^ Main action
   m b
  -- ^ Final action
   m (a, b)
generalFinally :: forall (m :: * -> *) a b. MonadWith m => m a -> m b -> m (a, b)
generalFinally m a
go m b
fin = forall (m :: * -> *) releaseReturn b a.
MonadWith m =>
GeneralAllocate m (WithException m) releaseReturn b a
-> (a -> m b) -> m (b, releaseReturn)
stateThreadingGeneralWith GeneralAllocate m (WithException m) b a ()
alloc forall a b. (a -> b) -> a -> b
$ forall a b. a -> b -> a
const m a
go
 where
  alloc :: GeneralAllocate m (WithException m) b a ()
alloc = forall (m :: * -> *) e releaseReturn releaseArg a.
((forall x. m x -> m x)
 -> m (GeneralAllocated m e releaseReturn releaseArg a))
-> GeneralAllocate m e releaseReturn releaseArg a
GeneralAllocate forall a b. (a -> b) -> a -> b
$ \forall x. m x -> m x
_  forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) e releaseReturn releaseArg a.
a
-> (GeneralReleaseType e releaseArg -> m releaseReturn)
-> GeneralAllocated m e releaseReturn releaseArg a
GeneralAllocated () GeneralReleaseType (WithException m) a -> m b
rel
  rel :: GeneralReleaseType (WithException m) a -> m b
rel GeneralReleaseType (WithException m) a
_ = m b
fin

instance MonadWith IO where
  stateThreadingGeneralWith :: forall releaseReturn b a.
GeneralAllocate IO (WithException IO) releaseReturn b a
-> (a -> IO b) -> IO (b, releaseReturn)
stateThreadingGeneralWith (GeneralAllocate (forall x. IO x -> IO x)
-> IO (GeneralAllocated IO (WithException IO) releaseReturn b a)
allocArg) a -> IO b
go = forall (m :: * -> *) b.
MonadMask m =>
((forall a. m a -> m a) -> m b) -> m b
mask forall a b. (a -> b) -> a -> b
$ \forall x. IO x -> IO x
restore  do
    GeneralAllocated a
res GeneralReleaseType SomeException b -> IO releaseReturn
releaseRes  (forall x. IO x -> IO x)
-> IO (GeneralAllocated IO (WithException IO) releaseReturn b a)
allocArg forall x. IO x -> IO x
restore
    b
b 
      forall x. IO x -> IO x
restore (a -> IO b
go a
res) forall (m :: * -> *) e a.
(MonadCatch m, Exception e) =>
m a -> (e -> m a) -> m a
`catch` \SomeException
e  do
        releaseReturn
_  GeneralReleaseType SomeException b -> IO releaseReturn
releaseRes forall a b. (a -> b) -> a -> b
$ forall e a. e -> GeneralReleaseType e a
ReleaseFailure SomeException
e
        forall (m :: * -> *) e a. (MonadThrow m, Exception e) => e -> m a
throwM SomeException
e
    releaseReturn
c  GeneralReleaseType SomeException b -> IO releaseReturn
releaseRes forall a b. (a -> b) -> a -> b
$ forall e a. a -> GeneralReleaseType e a
ReleaseSuccess b
b
    forall (f :: * -> *) a. Applicative f => a -> f a
pure (b
b, releaseReturn
c)

{- | A helper for [DerivingVia](https://ghc.gitlab.haskell.org/ghc/doc/users_guide/exts/deriving_via.html) a
'MonadWith' instance for any 'Monad'.

Note that the derived instance is only valid if the monad satisfies the "no continuation" condition, i.e.
that if execution of a computation exits a given lexical scope we are guaranteed that either all of the
actions within that scope have executed or the entire monadic computation has been terminated.

The most common factors violating "no continuation" are call/cc and exception catching. A monad which allows
exception /throwing/ but not catching is not thereby disqualified, as any thrown exception will of necessity
propagate until it terminates the entire monadic computation.
-}
newtype WithNoContinuation m a = WithNoContinuation (m a) deriving newtype (forall a b. a -> WithNoContinuation m b -> WithNoContinuation m a
forall a b.
(a -> b) -> WithNoContinuation m a -> WithNoContinuation m b
forall (m :: * -> *) a b.
Functor m =>
a -> WithNoContinuation m b -> WithNoContinuation m a
forall (m :: * -> *) a b.
Functor m =>
(a -> b) -> WithNoContinuation m a -> WithNoContinuation m 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 -> WithNoContinuation m b -> WithNoContinuation m a
$c<$ :: forall (m :: * -> *) a b.
Functor m =>
a -> WithNoContinuation m b -> WithNoContinuation m a
fmap :: forall a b.
(a -> b) -> WithNoContinuation m a -> WithNoContinuation m b
$cfmap :: forall (m :: * -> *) a b.
Functor m =>
(a -> b) -> WithNoContinuation m a -> WithNoContinuation m b
Functor, forall a. a -> WithNoContinuation m a
forall a b.
WithNoContinuation m a
-> WithNoContinuation m b -> WithNoContinuation m a
forall a b.
WithNoContinuation m a
-> WithNoContinuation m b -> WithNoContinuation m b
forall a b.
WithNoContinuation m (a -> b)
-> WithNoContinuation m a -> WithNoContinuation m b
forall a b c.
(a -> b -> c)
-> WithNoContinuation m a
-> WithNoContinuation m b
-> WithNoContinuation m 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 {m :: * -> *}.
Applicative m =>
Functor (WithNoContinuation m)
forall (m :: * -> *) a.
Applicative m =>
a -> WithNoContinuation m a
forall (m :: * -> *) a b.
Applicative m =>
WithNoContinuation m a
-> WithNoContinuation m b -> WithNoContinuation m a
forall (m :: * -> *) a b.
Applicative m =>
WithNoContinuation m a
-> WithNoContinuation m b -> WithNoContinuation m b
forall (m :: * -> *) a b.
Applicative m =>
WithNoContinuation m (a -> b)
-> WithNoContinuation m a -> WithNoContinuation m b
forall (m :: * -> *) a b c.
Applicative m =>
(a -> b -> c)
-> WithNoContinuation m a
-> WithNoContinuation m b
-> WithNoContinuation m c
<* :: forall a b.
WithNoContinuation m a
-> WithNoContinuation m b -> WithNoContinuation m a
$c<* :: forall (m :: * -> *) a b.
Applicative m =>
WithNoContinuation m a
-> WithNoContinuation m b -> WithNoContinuation m a
*> :: forall a b.
WithNoContinuation m a
-> WithNoContinuation m b -> WithNoContinuation m b
$c*> :: forall (m :: * -> *) a b.
Applicative m =>
WithNoContinuation m a
-> WithNoContinuation m b -> WithNoContinuation m b
liftA2 :: forall a b c.
(a -> b -> c)
-> WithNoContinuation m a
-> WithNoContinuation m b
-> WithNoContinuation m c
$cliftA2 :: forall (m :: * -> *) a b c.
Applicative m =>
(a -> b -> c)
-> WithNoContinuation m a
-> WithNoContinuation m b
-> WithNoContinuation m c
<*> :: forall a b.
WithNoContinuation m (a -> b)
-> WithNoContinuation m a -> WithNoContinuation m b
$c<*> :: forall (m :: * -> *) a b.
Applicative m =>
WithNoContinuation m (a -> b)
-> WithNoContinuation m a -> WithNoContinuation m b
pure :: forall a. a -> WithNoContinuation m a
$cpure :: forall (m :: * -> *) a.
Applicative m =>
a -> WithNoContinuation m a
Applicative, forall a. a -> WithNoContinuation m a
forall a b.
WithNoContinuation m a
-> WithNoContinuation m b -> WithNoContinuation m b
forall a b.
WithNoContinuation m a
-> (a -> WithNoContinuation m b) -> WithNoContinuation m b
forall {m :: * -> *}. Monad m => Applicative (WithNoContinuation m)
forall (m :: * -> *) a. Monad m => a -> WithNoContinuation m a
forall (m :: * -> *) a b.
Monad m =>
WithNoContinuation m a
-> WithNoContinuation m b -> WithNoContinuation m b
forall (m :: * -> *) a b.
Monad m =>
WithNoContinuation m a
-> (a -> WithNoContinuation m b) -> WithNoContinuation m 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 -> WithNoContinuation m a
$creturn :: forall (m :: * -> *) a. Monad m => a -> WithNoContinuation m a
>> :: forall a b.
WithNoContinuation m a
-> WithNoContinuation m b -> WithNoContinuation m b
$c>> :: forall (m :: * -> *) a b.
Monad m =>
WithNoContinuation m a
-> WithNoContinuation m b -> WithNoContinuation m b
>>= :: forall a b.
WithNoContinuation m a
-> (a -> WithNoContinuation m b) -> WithNoContinuation m b
$c>>= :: forall (m :: * -> *) a b.
Monad m =>
WithNoContinuation m a
-> (a -> WithNoContinuation m b) -> WithNoContinuation m b
Monad)

instance (Monad m)  MonadWith (WithNoContinuation m) where
  type WithException (WithNoContinuation m) = Void
  stateThreadingGeneralWith :: forall releaseReturn b a.
GeneralAllocate
  (WithNoContinuation m)
  (WithException (WithNoContinuation m))
  releaseReturn
  b
  a
-> (a -> WithNoContinuation m b)
-> WithNoContinuation m (b, releaseReturn)
stateThreadingGeneralWith (GeneralAllocate (forall x. WithNoContinuation m x -> WithNoContinuation m x)
-> WithNoContinuation
     m
     (GeneralAllocated
        (WithNoContinuation m)
        (WithException (WithNoContinuation m))
        releaseReturn
        b
        a)
allocArg) a -> WithNoContinuation m b
go = forall (m :: * -> *) a. m a -> WithNoContinuation m a
WithNoContinuation forall a b. (a -> b) -> a -> b
$ do
    let WithNoContinuation m (GeneralAllocated
     (WithNoContinuation m)
     (WithException (WithNoContinuation m))
     releaseReturn
     b
     a)
allocArg' = (forall x. WithNoContinuation m x -> WithNoContinuation m x)
-> WithNoContinuation
     m
     (GeneralAllocated
        (WithNoContinuation m)
        (WithException (WithNoContinuation m))
        releaseReturn
        b
        a)
allocArg forall a. a -> a
id
    GeneralAllocated a
res GeneralReleaseType Void b -> WithNoContinuation m releaseReturn
releaseRes  m (GeneralAllocated
     (WithNoContinuation m)
     (WithException (WithNoContinuation m))
     releaseReturn
     b
     a)
allocArg'
    let WithNoContinuation m b
go' = a -> WithNoContinuation m b
go a
res
    b
b  m b
go'
    let WithNoContinuation m releaseReturn
releaseRes' = GeneralReleaseType Void b -> WithNoContinuation m releaseReturn
releaseRes forall a b. (a -> b) -> a -> b
$ forall e a. a -> GeneralReleaseType e a
ReleaseSuccess b
b
    releaseReturn
c  m releaseReturn
releaseRes'
    forall (f :: * -> *) a. Applicative f => a -> f a
pure (b
b, releaseReturn
c)

deriving via WithNoContinuation (ST s) instance MonadWith (ST s)

deriving via WithNoContinuation Identity instance MonadWith Identity

instance (MonadWith m)  MonadWith (ReaderT r m) where
  type WithException (ReaderT r m) = WithException m
  stateThreadingGeneralWith
      a b releaseReturn
     . GeneralAllocate (ReaderT r m) (WithException m) releaseReturn b a
     (a  ReaderT r m b)
     ReaderT r m (b, releaseReturn)
  stateThreadingGeneralWith :: forall a b releaseReturn.
GeneralAllocate (ReaderT r m) (WithException m) releaseReturn b a
-> (a -> ReaderT r m b) -> ReaderT r m (b, releaseReturn)
stateThreadingGeneralWith (GeneralAllocate (forall x. ReaderT r m x -> ReaderT r m x)
-> ReaderT
     r
     m
     (GeneralAllocated
        (ReaderT r m) (WithException m) releaseReturn b a)
allocFun) a -> ReaderT r m b
go = forall r (m :: * -> *) a. (r -> m a) -> ReaderT r m a
ReaderT forall a b. (a -> b) -> a -> b
$ \r
r  do
    let
      allocFun'  ( x. m x  m x)  m (GeneralAllocated m (WithException m) releaseReturn b a)
      allocFun' :: (forall x. m x -> m x)
-> m (GeneralAllocated m (WithException m) releaseReturn b a)
allocFun' forall x. m x -> m x
restore = do
        let
          restore'   x. ReaderT r m x  ReaderT r m x
          restore' :: forall x. ReaderT r m x -> ReaderT r m x
restore' ReaderT r m x
mx = forall r (m :: * -> *) a. (r -> m a) -> ReaderT r m a
ReaderT forall a b. (a -> b) -> a -> b
$ forall x. m x -> m x
restore forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall r (m :: * -> *) a. ReaderT r m a -> r -> m a
runReaderT ReaderT r m x
mx
        GeneralAllocated a
x GeneralReleaseType (WithException m) b -> ReaderT r m releaseReturn
release  forall r (m :: * -> *) a. ReaderT r m a -> r -> m a
runReaderT ((forall x. ReaderT r m x -> ReaderT r m x)
-> ReaderT
     r
     m
     (GeneralAllocated
        (ReaderT r m) (WithException m) releaseReturn b a)
allocFun forall x. ReaderT r m x -> ReaderT r m x
restore') r
r
        let
          release' :: GeneralReleaseType (WithException m) b -> m releaseReturn
release' GeneralReleaseType (WithException m) b
relTy = forall r (m :: * -> *) a. ReaderT r m a -> r -> m a
runReaderT (GeneralReleaseType (WithException m) b -> ReaderT r m releaseReturn
release GeneralReleaseType (WithException m) b
relTy) r
r
        forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) e releaseReturn releaseArg a.
a
-> (GeneralReleaseType e releaseArg -> m releaseReturn)
-> GeneralAllocated m e releaseReturn releaseArg a
GeneralAllocated a
x GeneralReleaseType (WithException m) b -> m releaseReturn
release'
    forall (m :: * -> *) releaseReturn b a.
MonadWith m =>
GeneralAllocate m (WithException m) releaseReturn b a
-> (a -> m b) -> m (b, releaseReturn)
stateThreadingGeneralWith (forall (m :: * -> *) e releaseReturn releaseArg a.
((forall x. m x -> m x)
 -> m (GeneralAllocated m e releaseReturn releaseArg a))
-> GeneralAllocate m e releaseReturn releaseArg a
GeneralAllocate (forall x. m x -> m x)
-> m (GeneralAllocated m (WithException m) releaseReturn b a)
allocFun') (forall a b c. (a -> b -> c) -> b -> a -> c
flip forall r (m :: * -> *) a. ReaderT r m a -> r -> m a
runReaderT r
r forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> ReaderT r m b
go)

instance (MonadWith m)  MonadWith (ResourceT m) where
  type WithException (ResourceT m) = WithException m
  stateThreadingGeneralWith
      a b releaseReturn
     . GeneralAllocate (ResourceT m) (WithException m) releaseReturn b a
     (a  ResourceT m b)
     ResourceT m (b, releaseReturn)
  stateThreadingGeneralWith :: forall a b releaseReturn.
GeneralAllocate (ResourceT m) (WithException m) releaseReturn b a
-> (a -> ResourceT m b) -> ResourceT m (b, releaseReturn)
stateThreadingGeneralWith (GeneralAllocate (forall x. ResourceT m x -> ResourceT m x)
-> ResourceT
     m
     (GeneralAllocated
        (ResourceT m) (WithException m) releaseReturn b a)
allocFun) a -> ResourceT m b
go = forall (m :: * -> *) a. (IORef ReleaseMap -> m a) -> ResourceT m a
ResourceT forall a b. (a -> b) -> a -> b
$ \IORef ReleaseMap
st  do
    let
      allocFun'  ( x. m x  m x)  m (GeneralAllocated m (WithException m) releaseReturn b a)
      allocFun' :: (forall x. m x -> m x)
-> m (GeneralAllocated m (WithException m) releaseReturn b a)
allocFun' forall x. m x -> m x
restore = do
        let
          restore'   x. ResourceT m x  ResourceT m x
          restore' :: forall x. ResourceT m x -> ResourceT m x
restore' ResourceT m x
mx = forall (m :: * -> *) a. (IORef ReleaseMap -> m a) -> ResourceT m a
ResourceT forall a b. (a -> b) -> a -> b
$ forall x. m x -> m x
restore forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (m :: * -> *) a. ResourceT m a -> IORef ReleaseMap -> m a
unResourceT ResourceT m x
mx
        GeneralAllocated a
x GeneralReleaseType (WithException m) b -> ResourceT m releaseReturn
release  forall (m :: * -> *) a. ResourceT m a -> IORef ReleaseMap -> m a
unResourceT ((forall x. ResourceT m x -> ResourceT m x)
-> ResourceT
     m
     (GeneralAllocated
        (ResourceT m) (WithException m) releaseReturn b a)
allocFun forall x. ResourceT m x -> ResourceT m x
restore') IORef ReleaseMap
st
        let
          release' :: GeneralReleaseType (WithException m) b -> m releaseReturn
release' GeneralReleaseType (WithException m) b
relTy = forall (m :: * -> *) a. ResourceT m a -> IORef ReleaseMap -> m a
unResourceT (GeneralReleaseType (WithException m) b -> ResourceT m releaseReturn
release GeneralReleaseType (WithException m) b
relTy) IORef ReleaseMap
st
        forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ forall (m :: * -> *) e releaseReturn releaseArg a.
a
-> (GeneralReleaseType e releaseArg -> m releaseReturn)
-> GeneralAllocated m e releaseReturn releaseArg a
GeneralAllocated a
x GeneralReleaseType (WithException m) b -> m releaseReturn
release'
    forall (m :: * -> *) releaseReturn b a.
MonadWith m =>
GeneralAllocate m (WithException m) releaseReturn b a
-> (a -> m b) -> m (b, releaseReturn)
stateThreadingGeneralWith (forall (m :: * -> *) e releaseReturn releaseArg a.
((forall x. m x -> m x)
 -> m (GeneralAllocated m e releaseReturn releaseArg a))
-> GeneralAllocate m e releaseReturn releaseArg a
GeneralAllocate (forall x. m x -> m x)
-> m (GeneralAllocated m (WithException m) releaseReturn b a)
allocFun') (forall a b c. (a -> b -> c) -> b -> a -> c
flip forall (m :: * -> *) a. ResourceT m a -> IORef ReleaseMap -> m a
unResourceT IORef ReleaseMap
st forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> ResourceT m b
go)