hs-bindgen-1.0.0.0: src-internal/HsBindgen/Eff.hs
module HsBindgen.Eff (
Eff -- opaque
, Support -- opaque
, wrapEff
, unwrapEff
, runFoldIdentity
, runFoldReader
, runFoldState
) where
import Control.Monad.Reader (MonadReader, Reader, ReaderT (..))
import Control.Monad.State (MonadState (state), State)
import Data.IORef (IORef, atomicModifyIORef, newIORef, readIORef)
import Data.Tuple (swap)
import HsBindgen.Imports
{-------------------------------------------------------------------------------
'Eff' monad
We work mostly in @IO@, and limited by @MonadUnliftIO@,
but sometimes we need more effects: @Eff@ wrapping @ReaderT r IO@
pattern can mimic many other monads.
NOTE: This is intentionally /not/ a member of 'MonadCatch'. We use 'Eff'
primarily for folding, and exception handling in folding requires special
care. See detailed discussion of 'foldWithHandler' in the @clang@ bindings.
-------------------------------------------------------------------------------}
newtype Eff m a = Eff (ReaderT (Support m) IO a)
deriving newtype (
Functor
, Applicative
, Monad
, MonadIO
, MonadUnliftIO
)
getEff :: Eff m a -> ReaderT (Support m) IO a
getEff (Eff ma) = ma
wrapEff :: (Support m -> IO a) -> Eff m a
wrapEff = Eff . ReaderT
unwrapEff :: Eff m a -> Support m -> IO a
unwrapEff = runReaderT . getEff
-- | 'Control.Monad.Reader.ReaderT' argument required to support @m@
type family Support (m :: Star -> Star) :: Star
--
-- 'Identity'
--
type instance Support Identity = ()
runFoldIdentity :: Eff Identity a -> IO a
runFoldIdentity = ($ ()) . unwrapEff
--
-- 'Reader'
--
type instance Support (Reader r) = r
deriving newtype instance MonadReader r (Eff (Reader r))
runFoldReader :: r -> Eff (Reader r) a -> IO a
runFoldReader env = ($ env) . unwrapEff
--
-- 'State'
--
type instance Support (State s) = IORef s
instance MonadState s (Eff (State s)) where
state f = wrapEff $ \ref -> atomicModifyIORef ref (swap . f)
runFoldState :: s -> Eff (State s) a -> IO (a, s)
runFoldState s f = do
ref <- newIORef s
a <- unwrapEff f ref
(a,) <$> readIORef ref