假设我在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可以提供退出值,但我认为必须有一个更惯用的方法来做到这一点。
答案 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)。 (如果下游首先终止,那么上游进程没有任何关系,但是终止进程,因此提供退出代码没有任何意义。)