【问题标题】:Serializing values to JSON array with pipes使用管道将值序列化为 JSON 数组
【发布时间】:2015-11-01 11:11:18
【问题描述】:

我想将传入的值序列化为 JSON。每个值都有一个 toJSON 实例。最终结果应该是一个列表。当前代码如下:

import Pipes
import qualified Pipes.Prelude as P

-- assume a source of elements
main :: IO ()
main = runEffect $ source >-> P.map encode >-> P.stdoutLn

问题是这样每一行都包含一个有效的 JSON 对象,但我希望整个结果是可解析的。我希望在第一个对象之前输出一个[ 字符,然后是每个元素后跟一个逗号,最后是另一个]。我怎样才能用管道做到这一点?

当前输出:

$ prog
{"key": "value"}
{"key": "value"}

期望的输出:

$ prog
[{"key": "value"},
{"key": "value"}]

我找到了pipes-aeson,但我不明白我应该如何使用它提供的功能。

编辑:我修改了 ErikR 的答案以获得Consumer,但它没有输出右括号:

jsonExporter :: Consumer (FilePath, AnalysisResult) IO ()
jsonExporter = do
    lift $ putStr "["
    P.map encode >-> insertCommas
    lift $ putStr "]"

我不明白为什么。

【问题讨论】:

    标签: json haskell aeson haskell-pipes


    【解决方案1】:

    这个管段:

    for cat $ \x -> lift $ do { putStr ", "; putStrLn x }
    

    将在管道中的每个元素之前发出一个逗号。

    为了对第一个元素进行特殊处理,我们只需展开循环一次:

    insertCommas = do
      x1 <- await
      lift $ putStrLn x1      -- print first element w/o a comma
      for cat $ \x -> lift $ do { putStr ", "; putStrLn x }
    

    现在您可以将流式 JSON 管道编写为:

    putStr "["
    runEffect $ source >-> P.map encode >-> insertCommas
    putStrLn "]"
    

    【讨论】:

    • 太棒了!我还在习惯lift,有时我发现很难正确使用它。
    • 由于 Aeson 的 encode 返回一个 ByteString 我想我可以使用管道组包中的 intersperse 函数吗?我的意思不是insertCommas
    • 你可以试试,但我认为在Bytestring的每一对字符之间穿插一个字符。
    • 我需要一个Consumer,所以我修改了你的代码(我把它放在问题中)。但我不明白为什么关闭] 永远不会输出。
    • 这确实应该是一个新问题。作为管段insertCommas 永远不会返回,所以这就是为什么我在 runEffect 之外打印括号。
    猜你喜欢
    • 2011-09-21
    • 2016-12-29
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-11
    • 1970-01-01
    • 2014-03-05
    • 2019-12-17
    相关资源
    最近更新 更多