9

Pipes.Aeson 库公开了以下函数:

decode :: (Monad m, ToJSON a) => Parser ByteString m (Either DecodingError a)

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

问题是该文件包含多个对象(所有相同类型),我想在读取它们时折叠或缩小它们。

Pipes.Parse 提供:

foldAll :: Monad m => (x -> a -> x) -> x -> (x -> b) -> Parser a m b

但是正如你所看到的,这会返回一个新的解析器——我想不出一种方法来提供第一个解析器作为参数。

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

不过,这可能是完全错误的方法。

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

4

1 回答 1

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

的返回值intProducer有点吓人,但这仅意味着intProducer以解析错误和错误后未解析的字节结束,或者以原始生产者的返回值(()在我们的例子中)结束。

我们可以忽略返回值:

intProducer' :: Monad m => Producer Int m ()
intProducer' = intProducer >> return ()

并将生产者插入到折叠Pipes.Prelude,例如sum

main :: IO ()
main = do
    total <- P.sum intProducer'
    putStrLn $ show total

在 ghci 中:

λ :main
10

另请注意,这些函数纯粹和不纯粹地让您应用于 foldl 包中定义的生产者折叠

于 2014-05-17T19:54:58.890 回答