Haskell Pipes - 获取管道中最后一个Proxy的返回值

时间:2015-03-27 21:01:36

标签: haskell haskell-pipes

假设我在Haskell Pipes中有两个Proxy。它们代表了外部系统流程。

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

所以我将它们挂钩到Effect,就像这样:

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

Effect将从第一个ExitCode终止Proxy。通常这将是produce,而不是consume。什么是惯用的Pipes方法来获得consume的返回值,即使它没有先终止?

到目前为止,我认为如果不进行某种类似的带内信令,这是不可能的,因此consume知道流已完成。最后一个代理知道关闭的唯一方法是从await获取内容,因此我可以向它发送一个空ByteString来表示流已完成。虽然这感觉不对劲。我现在得到的是一个单独的MVar可以提供退出值,但我认为必须有一个更惯用的方法来做到这一点。

2 个答案:

答案 0 :(得分:4)

如果没有带内信令,Consumer永远不可能有"返回值"如果Producer先返回。如果生产者是return,则意味着必须阻止Consumer等待请求的值。 Consumer永远不会再次运行,因此永远不会有机会return,直到Consumer获得带有请求值的带内信号。

仅仅因为信令是带内并不意味着它需要" icky"。我们可以通过捕获{{1}将Producer转换为Producer转换为forall r' . r',我们知道它不会返回(它的返回类型为return)并将其转发到下游。如果另一个请求返回上游,我们执行此操作forever

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 <\\)

Consumer结束时,您需要明确处理值request时要执行的操作,但不是获取响应(在Right中),而是获得返回值上游生产者(在Left)。

答案 1 :(得分:2)

感谢。我想出的是像

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

这样当效果运行时,如果下游进程终止,我得到(Nothing,代码),或者如果上游进程首先终止,则得到(只是code1,code2)。 (如果下游首先终止,那么上游进程没有任何关系,但是终止进程,因此提供退出代码没有任何意义。)