gpt4 book ai didi

haskell - 如何将 Sink 变成 Conduit?

转载 作者:行者123 更新时间:2023-12-04 12:12:01 29 4
gpt4 key购买 nike

我正在尝试写一个 Conduit使用 attoparsec解析器。具体来说,给定 parseOne :: Parser T , 我想构建一个 Conduit ByteString m T重复地将解析器应用于输入并流式传输结果。

attoparsec-conduit报价 sinkParser转一个Parser变成 Sink ,但是我怎样才能把这个Sink变成 Conduit ?我正在寻找的是一个类似的功能:

conduitSink :: (Resource m) => Sink a m b -> Conduit a m b

它反复将数据输入 Sink ,产生每个结果。看起来它可以很容易地编写为手动循环,但我想知道是否有更好的方法。

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

最佳答案

您需要使用 SequencedSink 为此的系统;它使用接收器和跟踪状态从接收器生产者的重复应用中生成管道。

您创建的接收器已针对增量解析一个值进行了优化,该值将是管道序列结束时的结果。

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

例如,假设您的解析器解析 [--][----]等等,以及 TInt表示解析的破折号数,您需要跟踪解析器的状态,如下所示:

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.Attoparsec.ByteString.Result)作为传递状态;根据情况,不同的数据类型可能更合适。

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

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

编辑:简单地在一个循环中应用你的接收器确实是最简单的解决方案,但是如果你的解析器解析通常最终在字节 block 边界上的短片段,它将具有稍微不同的性能特征。

关于haskell - 如何将 Sink 变成 Conduit?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/9042833/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com