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

5

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

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

所以我将它们挂钩到一个效果中,就像这样:

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

这个 Effect 将会给我第一个终止的 ProxyExitCode。通常这将是 produce,而不是 consume。那么,在 Pipes 中如何以惯用方式获取 consume 的返回值,即使它没有先终止呢?
到目前为止,我认为这似乎不可能,除非进行某种令人讨厌的带内信号处理,以便 consume 知道流已经完成。最后一个 Proxy 关闭的唯一方法是通过从 await 获取某些内容,因此我可以发送一个空的 ByteString 来表示流已经完成。但这感觉不太对。现在我有一个单独的 MVar 可以提供退出值,但我认为必须有更加惯用的方法来做到这一点。
2个回答

5
没有内在的信号,如果生产者先返回,消费者就永远不可能有“返回值”。 如果生产者正在return,那意味着Consumer必须阻塞等待请求的值。 Consumer将永远不会再次运行,因此永远没有机会return,直到Consumer得到带有所请求值的内在信号。
仅仅因为信号是内部的,这并不意味着它必须很繁琐。我们可以通过捕获return并将其向下转发来将可能返回的Producer转换为我们知道不会返回的Producer(其返回类型为forall r' . r')。 为了防止上游返回另一个请求,我们在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 <\\)

在消费者端,您需要明确处理当请求值时发生什么情况,但是您没有收到响应(在Right中),而是收到上游生产者的返回值(在Left中)。


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) 的结果。如果下游先终止,就没有必要再进行上游进程的操作了,因此提供退出代码是没有意义的。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接