使用Haskell pipes库,我尝试使用以下类型定义Pipe
:
signalExhausted :: Monad m => Pipe a (Value a) m r
其中Value
数据类型由:
data Value a = Value a | Exhausted
管道应遵守以下法律:
toList (each [] >-> signalExhausted) == [Exhausted]
toList (each xs >-> signalExhausted) == map Value xs ++ [Exhausted]
换句话说,管道应该等同于Pipes.Prelude.map Value
,除了在处理完所有上游值后它应该产生额外的Exhausted
,使下游有机会执行一些最终操作。 / p>
可以定义这样的Pipe
吗?
> let xs = words "hubble bubble toil and trouble"
> toList $ each xs >-> signalExhausted
[Value "hubble", Value "bubble", Value "toil", Value "and", Value "trouble", Exhausted]
我知道pipes-parse
库提供了draw
和parseForever
功能。这些看起来很有用,但我不太清楚如何将它们组合成符合上述规范的Pipe
。
答案 0 :(得分:4)
无法定义像signalExhausted
这样的管道,但是相当于(>-> signalExhausted)
的功能可以。
>->
是pull
category的专用版本。下游代理从上游代理中提取数据来驱动执行。下游代理向上游发送空请求()
并阻塞,直到保持值的响应从上游代理返回。当上游代理用尽并且没有更多值要发回时,它return
。您可以在each
的定义中看到对这些示例很重要的return
。
each = F.foldr (\a p -> yield a >> p) (return ())
-- what to do when the data's exhausted ^
下游代理需要一个值才能继续运行,但管道库可能没有提供它的值,因此下游代理永远不会再运行。由于它永远不会再次运行,因此无法修改或响应数据。
这个问题有两个解决方案。最简单的方法是在上游管道上map
Value
,并在完成后添加yield Exhausted
。
import Pipes
import qualified Pipes.Prelude as P
data Value a = Value a | Exhausted
deriving (Show)
signalExhausted p = p >-> P.map Value >> yield Exhausted
除了功能signalExhausted
取代(>-> signalExhausted)
之外,这正是您正在寻找的内容。
let xs = words "hubble bubble toil and trouble"
print . P.toList . signalExhausted $ each xs
[Value "hubble",Value "bubble",Value "toil",Value "and",Value "trouble",Exhausted]
这个问题的更一般的解决方案是停止上游代理返回,而是在耗尽时向下游发出信号。我在answer to a related question中演示了如何执行此操作。
import Control.Monad
import Pipes.Core
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 <\\)
这会将每个respond
替换为respond . Right
,并将return
替换为forever . respond . left
,并将回复和响应一起发送到下游。
returnDownstream
比您正在寻找的更为通用。我们可以演示如何使用它来重新创建signalExhausted
。 returnDownstream
转换回一个永不返回的管道,然后将其返回值作为Left
的{{1}}值转发到下游。
Either
signalExhausted p = returnDownstream p >-> respondLeftOnce
是一个示例下游代理。下游代理可以识别respondLeftOnce
中保留的常规值和Right
中保存的返回值。
Left