1

我认为这对我来说有点先进,但我的目标是从 http API 获取原始 json,从中解析第一个列表,做我需要做的任何事情,然后转到下一个列表,等等上。我希望这一次只允许将一个列表加载到内存中(每个列表都非常小,但 json 中有很多列表)。我用 Aeson 试了一下,它吃掉了所有的 ram,没完没了地处理了好几个小时,最后我不得不杀了它。

如果我理解正确,httpSink 应该是要走的路,也许用 json-stream 来做实际的解析。我阅读了有关导管的教程,但我显然无法正确理解它,因为我无法做到这一点。

我知道如何使用 parseByteString 以我需要的方式解码 ByteString(至少我的测试似乎有效),但我想不出一种方法来使用 parseByteString 作为 httpSink 的第二个参数的接收器。我是否遗漏了一些明显的东西,或者我误解了管道的工作方式?

谢谢

4

2 回答 2

2

我还没有测试过这个,因为老实说我对这个库不太熟悉,但我认为这个适配器函数可以使它与管道一起工作:

module Data.JsonStream.Parser.Conduit
  ( jsonConduit
  , JsonStreamException (..)
  ) where

import Data.Conduit
import Data.JsonStream.Parser
import Data.ByteString (ByteString)
import Control.Monad.Catch
import Data.Typeable

jsonConduit
  :: MonadThrow m
  => Parser a
  -> ConduitM ByteString a m ()
jsonConduit =
    go . runParser
  where
    go (ParseYield x p) = yield x >> go p
    go (ParseNeedData f) = await >>= maybe
      (throwM JsonStreamNotEnoughData)
      (go . f)
    go (ParseFailed str) = throwM $ JsonStreamException str
    go (ParseDone bs) = leftover bs

data JsonStreamException
  = JsonStreamException !String
  | JsonStreamNotEnoughData
  deriving (Show, Typeable)
instance Exception JsonStreamException
于 2017-10-01T16:01:28.370 回答
0

你写了:

我阅读了有关导管的教程,但我显然无法正确理解它,因为我无法做到这一点。

 

我想不出一种方法来使用 parseByteString 作为 httpSink 的第二个参数的接收器。

这里的问题是,这Sink只是管道的简写:

type Sink i m r = ConduitM i Void m r

ASink是一种没有下游组件的管道。

导管是您需要的解决方案,我认为是您阅读的教程。如果您对其中的某些概念不满意,请尝试询问有关它的特定问题。

于 2017-10-01T08:47:53.247 回答