How to interoperate with concurrent monad transformers
sullyj3 opened this issue · 6 comments
I'm trying to use effectful
together with streamly
. I have a SerialT (Eff es) a
, which uses streamly's concurrency combinators internally (async
and fromAsync
). I'm getting the runtime error:
If you want to use the unlifting function to run Eff computations in multiple threads, have a look at UnliftStrategy (ConcUnlift).
I had a look at the docs for ConcUnlift
, but I'm struggling to understand how and where to use it. I had hoped I could just use it at the the entry point to my program, and maybe it would work but just be a little slower than if it was targeted more specifically:
-- (simplified)
main :: IO ()
main = do
config <- getConfig
runEff .
withUnliftStrategy (ConcUnlift Ephemeral Unlimited) .
runFailIO .
runReader config $
myProgram
But it doesn't seem to solve the problem - it still results in the same runtime error. Would it be possible to get some relevant examples in the documentation?
It's a bit unclear without full example, but if you look at the documentation of withEffToIO, it says that the strategy is reset to SeqUnlift inside a continuation (that's the same function that MonadUnliftIO and MonadBaseControl instances use).
Though you're the second person that finds it surprising, so perhaps it shouldn't do that.
I'm pretty sure not resetting the strategy is the correct choice either way, because if it's reset, then it's impossible to re-use external pieces of code that use unlifting and spawn more than one level of threads.
For some reason I didn't think of this scenario before 😞
Thanks for the rapid response! Works perfectly, thank you! Although I don't really understand why, since I'm not calling withEffToIO
. Is that happening under the hood somewhere? I think I'm just generally confused about where and why unlifting is occurring.
Is that happening under the hood somewhere?
Yes, instances of MonadUnliftIO
/ MonadBaseControl IO
use this function.
Ah, that makes sense.