Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Why was this done to MonadResource? #431

Open
ghost opened this issue Feb 7, 2020 · 3 comments
Open

Why was this done to MonadResource? #431

ghost opened this issue Feb 7, 2020 · 3 comments

Comments

@ghost
Copy link

ghost commented Feb 7, 2020

Here is example of people talking. MonadResource did something useful for them, but since the unliftio change, MonadResource became useless. Why was a popular "standard" type class in the Haskell community damaged like this?

What can be done, if anything?

@ghost
Copy link
Author

ghost commented Feb 8, 2020

This is where they rely on MonadBaseControl. They're using it "for saving and restoring the state of monad when we fork a concurrent thread". Here's the code where they use it. Can they achieve their aims without using MonadBaseControl?

------------------------------------------------------------------------------
-- Spawning threads
------------------------------------------------------------------------------

-- | A monad that can perform concurrent or parallel IO operations. Streams
-- that can be composed concurrently require the underlying monad to be
-- 'MonadAsync'.
--
-- @since 0.1.0
type MonadAsync m = (MonadIO m, MonadBaseControl IO m, MonadThrow m)

-- When we run computations concurrently, we completely isolate the state of
-- the concurrent computations from the parent computation.  The invariant is
-- that we should never be running two concurrent computations in the same
-- thread without using the runInIO function.  Also, we should never be running
-- a concurrent computation in the parent thread, otherwise it may affect the
-- state of the parent which is against the defined semantics of concurrent
-- execution.
newtype RunInIO m = RunInIO { runInIO :: forall b. m b -> IO (StM m b) }

captureMonadState :: MonadBaseControl IO m => m (RunInIO m)
captureMonadState = control $ \run -> run (return $ RunInIO run)

-- Stolen from the async package. The perf improvement is modest, 2% on a
-- thread heavy benchmark (parallel composition using noop computations).
-- A version of forkIO that does not include the outer exception
-- handler: saves a bit of time when we will be installing our own
-- exception handler.
{-# INLINE rawForkIO #-}
rawForkIO :: IO () -> IO ThreadId
rawForkIO action = IO $ \ s ->
   case fork# action s of (# s1, tid #) -> (# s1, ThreadId tid #)

{-# INLINE doFork #-}
doFork :: MonadBaseControl IO m
    => m ()
    -> RunInIO m
    -> (SomeException -> IO ())
    -> m ThreadId
doFork action (RunInIO mrun) exHandler =
    control $ \run ->
        mask $ \restore -> do
                tid <- rawForkIO $ catch (restore $ void $ mrun action)
                                         exHandler
                run (return tid)

Code BSD3- licensed, taken from here: https://github.com/composewell/streamly/blob/v0.7.0/src/Streamly/Internal/Data/SVar.hs#L888

@ghost
Copy link
Author

ghost commented Feb 19, 2020

@bitemyapp Unfortunately, I'm not sure we can do without it. If we can, great. If not, we'd have proof that resourcet can no longer do things it previously could. I don't have enough expertise to establish which.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant