Polysemy: Tactics binding deprecated workaround
In a previous log, we ended with a solution for Resource
which wasn't Error
resistant.
The solution is to use the soo-deperecated withLowerToIO
.
Let's start again with our simpler effect
data BindE (m :: Type -> Type) a where
BindE :: m a -> (a -> m b) -> BindE m b
makeSem ''BindE
We can express an impure (Embed
-base) interpreter:
interpretBindTacticLowering =
interpretH $
\case
BindE f g -> do
ma <- runT f
mf <- bindT g
withLowerToIO $ \lower _ -> do
let toIO :: Sem (BindE ': r) x -> IO x
toIO = lower . raise . interpretBindTacticLowering
toIO ma >>= toIO . mf
withLowerToIO
provides two functions (one to locally interpret a Sem r a
to IO a
and a finalizer) and expect a IO a
, it's defined as:
withLowerToIO
:: Member (Embed IO) r
=> ((forall x. Sem r x -> IO x) -> IO () -> IO a)
-> Sem r a
Under the hood, a thread is created (the program should be compiled with -thread
) to run the effect stack until IO
, 'blocking' thread.
The finalizer does not need to be called, but it indicate the end of the new thread.
Let's see how it goes for Resource
:
data Resource m a where
Bracket :: m a -> (a -> m c) -> (a -> m b) -> Resource m b
We are now able to use bracket
:
resourceToIO =
interpretH $
\case
Bracket alloc dealloc use -> do
alloc' <- runS alloc
dealloc' <- bindS dealloc
use' <- bindS use
withLowerToIO $ \lower finish -> do
let runHoE :: Sem (Resource ': r) x -> IO x
runHoE = lower . raise . resourceToIO
Expection.bracket
(runHoE alloc')
(\x -> runHoE (use' x) >> finish)
(runHoE . dealloc')