Let's say I have two Proxy
in Haskell Pipes. They represent external system processes.
produce :: MonadIO m => Producer ByteString m ExitCode
consume :: MonadIO m => Consumer ByteString m ExitCode
So I hook them into an Effect
, like this:
effect :: Effect m ExitCode
effect = produce >-> consume
This Effect
is going to give me the ExitCode
from the first Proxy
that terminates. Ordinarily this will be the produce
, not the consume
. What's the idiomatic Pipes way to get the return value of the consume
even if it does not terminate first?
So far I am thinking this is not possible without doing some sort of icky in-band signaling so the consume
knows the stream is done. The only way the last Proxy knows to shut down is by getting something from an await
, so I could send it an empty ByteString
to signal that the stream is done. That just doesn't feel right though. What I've got now is a separate MVar that can provide the exit value but I'm thinking there has to be a more idiomatic way to do this.
Without in-band signaling it will never be possible for the Consumer
to have a "return value" if the Producer
returns first. If the producer is return
ing that means the Consumer
must be blocked waiting for a requested value. The Consumer
will never run again, and thus never have an opportunity to return
, until the Consumer
gets an in-band signal with the requested value.
Just because signaling is in-band doesn't mean it needs to be "icky". We can convert a Producer
that might return into a Producer
that we know doesn't return (it's return type is forall r' . r'
) by capturing the return
and forwarding it downstream. We do this forever
in case another request comes back upstream.
returnDownstream :: Monad m => Proxy a' a b' b m r -> Proxy a' a b' (Either r b) m r'
returnDownstream = (forever . respond . Left =<<) . (respond . Right <\\)
At the Consumer
end you need to explicitly handle what to do when a value is request
ed but instead of getting the response (in a Right
) you get the return value of the upstream producer (in a Left
).