Haskell Pipes - get the return value of the last proxy in the pipeline

Let's say I have two Proxy in Haskell Pipes. They are external system processes.

 produce :: MonadIO m => Producer ByteString m ExitCode consume :: MonadIO m => Consumer ByteString m ExitCode 

Therefore, I bind them to Effect , for example:

 effect :: Effect m ExitCode effect = produce >-> consume 

This Effect is going to give me an ExitCode from the first Proxy that completes. Usually it will be produce , not consume . How can idiomatic channels get the consume return value even if it doesn't end first?

So far, I think this is not possible without any inoperative in-band signaling, so consume knows that the thread has completed. The only way the last proxy knows to close is to get something from await , so I can send it an empty ByteString to signal that the thread has completed. It just doesn't seem right. Now I have a separate MVAR that can provide an output value, but I think there should be a more idiomatic way for this.

+4
source share
2 answers

Without in-band signaling, it will never be possible for Consumer have a โ€œreturn valueโ€ if Producer returns first. If the manufacturer is returning, this means that the Consumer must be locked in anticipation of the required value. Consumer will never start again and therefore will never be able to return until Consumer receives an in-band signal with the requested value.

Just because an alarm within a range does not mean that it should be icky. We can transform the Producer , which can return to the Producer , which, as we know, does not return (its return type is forall r' . r' ), capture return and redirect it downstream. We do this forever if another request comes back.

 returnDownstream :: Monad m => Proxy a' ab' bmr -> Proxy a' ab' (Either rb) mr' returnDownstream = (forever . respond . Left =<<) . (respond . Right <\\) 

At the end of Consumer you need to explicitly handle what to do when the request ed value, but instead of receiving a response (in Right ), you get the return value of the upstream producer (in Left ).

+4
source

Thanks. What I came up with is something like

 produce :: MonadIO m => Producer (Either ExitCode ByteString) mr consume :: MonadIO m => Consumer (Either ExitCode ByteString) m (Maybe ExitCode, ExitCode) 

so when the Effect starts, I get (Nothing, code) if the downstream process ends, or (Just code1, code2) if the previous process completed first. (If the downstream ends first, then there is nothing to do with the upstream process, but terminating it, so providing an exit code does not make any sense.)

+2
source

All Articles