Each await/yield (Request/Respond constructors) inside a pipe unmask operation results in switching to a new mask/unmask pair in the base monad. This means the current unmask operation must be retrieved for each new block of wrapped base monad operations (M constructors) inside a pipe unmask. The current code doesn't do this. #15
Here is some code that demonstrates this by tracking the mask/unmask operations paris in the base monad via StateT and printing out which is which. The core of the code is
trace :: MonadIO m => String -> m a -> m a
trace m ia = do
liftIO (putStrLn ("begin " ++ m))
a <- ia
liftIO (putStrLn ("end " ++ m))
return a
examplep :: (MonadIO m, MonadCatch m) => (forall q. Producer () m q -> Producer () m q) -> Producer () m ()
examplep unmask =
trace "Proxy unmask" $
unmask $ trace "yield (output functions as original two IO calls)" $ yield ()
devnullp :: Monad m => Consumer a m ()
devnullp = await >> devnullp
main :: IO ()
main = evalTraceT . runEffect $
trace "Proxy mask" $
mask examplep >-> devnullp
and running it shows the incorrect use of the original unmask operation inside the subsequent mask operation following the yield
begin Proxy mask
begin StateT mask 0
begin Proxy unmask
begin StateT unmask 0
begin yield (output functions as original two IO calls)
end StateT unmask 0
end StateT mask 0
begin StateT mask 1
begin StateT unmask 0
end yield (output functions as original two IO calls)
end StateT unmask 0
begin StateT unmask 0
end StateT unmask 0
end Proxy unmask
end StateT mask 1
end Proxy mask
Here is some code that demonstrates this by tracking the mask/unmask operations paris in the base monad via StateT and printing out which is which. The core of the code is
and running it shows the incorrect use of the original unmask operation inside the subsequent mask operation following the yield