Haskell 我怎样才能把水槽变成管道?

Haskell 我怎样才能把水槽变成管道?,haskell,conduit,Haskell,Conduit,我正在尝试使用解析器编写一个管道。具体地说,给定parseOne::Parser T,我想通过testring mt构建一个管道,它重复地将解析器应用于输入并流式传输结果 提供sinkParser将解析器转换为接收器,但如何将此接收器转换为导管?我要找的是这样一个函数: conduitSink :: (Resource m) => Sink a m b -> Conduit a m b 它重复地将数据输入接收器,并在运行时生成每个结果。它似乎可以相当容易地编写为手动循环,但我想知道

我正在尝试使用解析器编写一个
管道
。具体地说,给定
parseOne::Parser T
,我想通过testring mt构建一个
管道,它重复地将解析器应用于输入并流式传输结果

提供
sinkParser
解析器
转换为
接收器
,但如何将此
接收器
转换为
导管
?我要找的是这样一个函数:

conduitSink :: (Resource m) => Sink a m b -> Conduit a m b
它重复地将数据输入
接收器
,并在运行时生成每个结果。它似乎可以相当容易地编写为手动循环,但我想知道是否有更好的方法

导管库中缺少这个看似显而易见的功能,这让我觉得我可能做错了什么;有没有更好的方法来实现这一点?用例将原始字节转换为基于消息的网络协议的解析形式,由管道的后续阶段处理。由于,我已经有了相反的方向(即,
导管T m ByteString
),因此这似乎是构造事物的最自然的方式。

您需要使用系统来实现这一点;它使用接收器和跟踪状态从接收器生成器的重复应用生成导管

您创建的接收器经过优化,可以增量解析一个值,该值将是导管序列末尾的结果

但是,由于您希望它成为管道的一部分,并且传入的
ByteString
的每个块可能与您的解析器匹配一次或多次,因此您需要注意对解析过程进行更细粒度的控制,在接收器的每个应用程序之间传递未完成解析的状态

例如,假设您的解析器解析
[-]
[-]
等,并且
T
Int
表示解析的破折号,您需要跟踪解析器的状态,如下所示:

Input chunk    Sink result - Data.Conduit.SequencedSinkResponse
[--][---]      Emit Nothing [2, 3]
[---][---      Emit (Just #func) [3]
---------      Emit (Just #func) []
]              Emit Nothing [12]
               Stop
在本例中,我使用
Maybe(ByteString->Data.attopassec.ByteString.Result)
作为传递状态;根据具体情况,不同的数据类型可能更合适

这种明确的水流处理需要保持管道的管道性质;让解析器管道成为一个“瓶颈”,总是等待足够的数据块来满足解析器,这将是一个主要的性能下降点

使用可用的
ResourceT
monad接口,所需接收器的实现应该相当简单


编辑:简单地在循环中应用接收器确实是最简单的解决方案,但如果解析器解析通常位于字节块边界上的短片段,则它的性能特征会略有不同。

谢谢,我将尝试一下。这是否意味着我根本不会使用ATOPASSEC导管?如果是这样的话,使用这种技术将通用的
conduitParser::(AttoparsecInput a,resourcetrow m)=>Parser a b->conduct a m b
添加到它的接口上会有什么障碍吗?还是一个简单的省略?@ehird,我相信这只是一个省略;当前的
sinkParser
代码表明,它可以很容易地被转换为多次解析输入流,因为它使用了与我前面描述的类似的技术,只是在第一次解析后它停止使用输入;我可能会使用这个实现。顺便说一句,谢谢你让我知道SequencedSink的事;我在阅读文档时忽略了它。