使用Pipes.Aeson在Haskell中流式解析JSON

imm*_*ate 9 parsing json haskell aeson haskell-pipes

Pipes.Aeson库公开以下函数:

decode :: (Monad m, ToJSON a) => Parser ByteString m (Either DecodingError a)
Run Code Online (Sandbox Code Playgroud)

如果我将evalStateT与此解析器和文件句柄作为参数一起使用,则会从文件中读取单个JSON对象并进行解析.

问题是文件包含几个对象(所有类型都相同),我想在阅读时折叠或缩小它们.

Pipes.Parse提供:

foldAll :: Monad m => (x -> a -> x) -> x -> (x -> b) -> Parser a m b
Run Code Online (Sandbox Code Playgroud)

但是你可以看到这会返回一个新的解析器 - 我想不出提供第一个解析器作为参数的方法.

看起来Parser实际上是StateT monad变换器中的Producer.我想知道是否有一种从StateT中提取Producer的方法,以便evalStateT可以应用于foldAll Parser,以及解码Parser中的Producer.

这可能完全是错误的方法.

我的问题,简而言之:
使用Pipes.Aeson解析文件时,折叠文件中所有对象的最佳方法是什么?

dan*_*iaz 5

而不是使用的decode,可以使用解析镜头的.它将生产者转变为解析的JSON值的生产者.decoded Pipes.Aeson.UncheckedByteString

{-# LANGUAGE OverloadedStrings #-}

module Main where

import Pipes
import qualified Pipes.Prelude as P
import qualified Pipes.Aeson as A
import qualified Pipes.Aeson.Unchecked as AU
import qualified Data.ByteString as B

import Control.Lens (view)

byteProducer :: Monad m => Producer B.ByteString m ()
byteProducer = yield "1 2 3 4"

intProducer :: Monad m => Producer Int m (Either (A.DecodingError, Producer B.ByteString m ()) ())
intProducer = view AU.decoded byteProducer
Run Code Online (Sandbox Code Playgroud)

返回值intProducer有点可怕,但它只表示intProducer在解析错误和错误后的未解析字节或原始生成器的返回值(()在我们的例子中)完成.

我们可以忽略返回值:

intProducer' :: Monad m => Producer Int m ()
intProducer' = intProducer >> return ()
Run Code Online (Sandbox Code Playgroud)

并将制作人插入折叠Pipes.Prelude,例如sum:

main :: IO ()
main = do
    total <- P.sum intProducer'
    putStrLn $ show total
Run Code Online (Sandbox Code Playgroud)

在ghci:

? :main
10
Run Code Online (Sandbox Code Playgroud)

另请注意,这些函数纯粹不可避免地允许您应用于foldl包中定义的生成器折叠.

  • 你也可以做`缩放解码(foldAll step begin done)` (2认同)