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

Oma*_*man 5 haskell haskell-pipes

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

produce :: MonadIO m => Producer ByteString m ExitCode
consume :: MonadIO m => Consumer ByteString m ExitCode
Run Code Online (Sandbox Code Playgroud)

所以我把它们挂在一个Effect,像这样:

effect :: Effect m ExitCode
effect = produce >-> consume
Run Code Online (Sandbox Code Playgroud)

这将从终止的第一个Effect开始给我。通常,这将是,而不是。即使它没有首先终止,获得返回值的惯用 Pipes 方法是什么?ExitCodeProxyproduceconsumeconsume

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

Cir*_*dec 5

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

仅仅因为信令是带内的并不意味着它需要“讨厌”。我们可以通过捕获并将其向下游转发,将Producer可能返回的 a转换为Producer我们知道不会返回的 a (它的返回类型是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 <\\)
Run Code Online (Sandbox Code Playgroud)

Consumer最后,你需要明确地处理当值做什么request编而是获得响应(在Right)你得到的上游生产商的返回值(在Left)。