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

Interoperability with libraries using MonadBaseControl IO #477

Closed
drlkf opened this issue Apr 5, 2023 · 10 comments
Closed

Interoperability with libraries using MonadBaseControl IO #477

drlkf opened this issue Apr 5, 2023 · 10 comments

Comments

@drlkf
Copy link

drlkf commented Apr 5, 2023

Say I want to implement a function using lifted-async such as:

runStreamingCommand :: Members [Embed IO, Error CustomError] r
  => (String, [String])
  -> (ByteString -> Sem r ())
  -> (ByteString -> Sem r ())
  -> Sem r ()
runStreamingCommand (cmd, args) stdoutHandler stderrHandler = do
  (ClosedStream, pOut, pErr, cph) <- streamingProcess $ proc cmd args

  let stdout = runConduit $ pOut .| CL.mapM_ stdoutHandler
      stderr = runConduit $ pErr .| CL.mapM_ stderrHandler

  exit <- runConcurrently $
    Concurrently stdout *>
    Concurrently stderr *>
    Concurrently (waitForStreamingProcess cph)

  case exit of
    ExitSuccess      -> return ()
    ExitFailure code -> throw $ CommandError cmd code

Since Concurrently m can only derive an Applicative instance if m has an instance of MonadBaseControl IO, I can't construct my application to pass to runConcurrently:

    • Could not deduce (MonadBaseControl IO (Sem r))
        arising from a use of ‘*>’
      from the context: Members '[Embed IO, Error CustomError] r

I'm not competent enough to figure this out myself I'm sorry to say, since I have next to zero understanding of MonadBaseControl, and I'm not an expert on polysemy's machinery either. Is there an obvious solution I missed, or is some implementation required to interoperate those two things ?

@tek
Copy link
Member

tek commented Apr 5, 2023

There's no comfortable solution, you'll have to lower to the final IO. Something like

foo = withWeavingToFinal \ s lower ex -> do
  let stdout = runConduit $ pOut .| CL.mapM_ (\ x -> lower (stdoutHandler x <$ s))
      stderr = runConduit $ pErr .| CL.mapM_ (\ x -> lower (stderrHandler x <$ s))

  exit <- runConcurrently $
    Concurrently stdout *>
    Concurrently stderr *>
    Concurrently (waitForStreamingProcess cph)

  case exit of
    ExitSuccess      -> return (() <$ s)
    ExitFailure code -> throw $ CommandError cmd code

@drlkf
Copy link
Author

drlkf commented Apr 6, 2023

Is it impossible to implement instance Member (Embed IO) r => MonadBaseControl IO (Sem r) ?

@tek
Copy link
Member

tek commented Apr 6, 2023

yeah, liftBaseWith is a rank 2 function with IO in both positive and negative position, and we can't handle that

@tek
Copy link
Member

tek commented Apr 6, 2023

it would be possible for Strategic, I think. but there you're already in IO

@drlkf
Copy link
Author

drlkf commented Apr 6, 2023

What would you recommend as a proper solution to this ? I want to run a process and apply my combined effects to its outputs (stdout and stderr) in a streaming manner. Maybe lifted-async was the wrong approach ?

@tek
Copy link
Member

tek commented Apr 6, 2023

personally I use this for processes and a Queue or Events for the concurrency part.

But I think for your case the Final method should be fine, if you're only performing side effects.

@drlkf
Copy link
Author

drlkf commented Apr 6, 2023

Does that mean I should switch from Embed to Final in my whole monad stack then ?

@tek
Copy link
Member

tek commented Apr 6, 2023

you can use both in different places if you don't want to change everything.

@drlkf
Copy link
Author

drlkf commented Apr 6, 2023

Alright. Thanks for your help

@drlkf drlkf closed this as not planned Won't fix, can't repro, duplicate, stale Apr 6, 2023
@arybczak
Copy link

What would you recommend as a proper solution to this ?

Switching to a different effect library that provides both MonadUnliftIO and MonadBaseControl IO instances for a rainy day as well as full-power bindings to the async library as an effect.

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

3 participants