5

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

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,而不是consumeconsume即使它没有首先终止,获取返回值的惯用管道方法是什么?

到目前为止,我认为如果不执行某种 icky 带内信令,这是不可能的,因此consume知道流已完成。最后一个 Proxy 知道要关闭的唯一方法是从 中获取一些东西await,所以我可以向它发送一个空ByteString来表示流已完成。只是感觉不对。我现在拥有的是一个单独的 MVar,它可以提供退出值,但我认为必须有一种更惯用的方式来做到这一点。

4

2 回答 2

5

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

仅仅因为信令是带内的并不意味着它需要是“icky”。我们可以通过捕获并将其转发到下游,将Producer可能返回的 a转换为Producer我们知道不会返回的(它的返回类型是)。我们这样做是为了防止另一个请求从上游返回。forall r' . r'returnforever

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编辑时要做什么,而不是获取响应(在 a 中Right),而是获取上游生产者的返回值(在 a 中Left)。

于 2015-03-27T21:50:57.890 回答
2

谢谢。我想出的是类似的东西

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

这样当效果运行时,如果下游进程终止,我会得到一个 (Nothing, code),如果上游进程首先终止,我会得到一个 (Just code1, code2)。(如果下游首先终止,则上游进程与上游进程没有任何关系,而是终止它,因此提供退出代码没有任何意义。)

于 2015-03-28T02:01:30.107 回答