I'm writing a Monad transformer, and to run the transformer I need to spawn an IO thread that writes elements to a TQueue that the main thread has access to. However, none of the versions of withAsync provide the right signature. I need one with a signature something like
(MonadIO m) => IO a -> (Async a -> m b) -> m b
I tried lifted-async, but that had a lot of restrictions and had both the main and spawned thread in the same Monad.
Alternatively, since Control.Concurrent.Async says that withAsync is equivalent to
withAsync action inner = mask $ \restore -> do
a <- async (restore action)
restore (inner a) `finally` uninterruptibleCancel a
An alternate solution would be a version of mask that has a type signature something like
mask :: (MonadMask m) => ((forall a n. (MonadMask n) => n a -> n a) -> m b) -> m b
The closest I came to a solution was the following code, which I'm pretty sure doesn't work, but I can't be sure since I don't fully understand how mask works.
withAsyncT :: (MonadIO m, MonadMask m) => IO a -> (Async a -> m b) -> m b
withAsyncT action inner = mask $ \restore -> do
a <- liftIO $ asyncWithUnmask (\rstr -> rstr action)
restore (inner a) `finally` (liftIO $ uninterruptibleCancel a)
Is there a reasonable solution to get such a withAsync? Or do I have to use something like unliftio?