0

I'd like to serialize incoming values to JSON. Every value has a toJSON instance. The end result should be a list. The current code is the following:

import Pipes
import qualified Pipes.Prelude as P

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

The problem is that in this way every line contains a valid JSON object, but I want the whole result to be parseable. I'd like that before the first object a [ character is outputted, then every element followed by a comma, and finally another ]. How can I do this with pipes?

Current output:

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

Desired output:

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

I found pipes-aeson but I don't understand how should I use the functions it provides.

EDIT: I modified ErikR's answer to get a Consumer, but it does not output the closing bracket:

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

I cannot understand why.

1 Answer 1

1

This pipe segment:

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

will emit a comma before each element in the pipe.

To give the first element special treatment, we just unroll the loop once:

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

Now you can write your streaming JSON pipeline as:

putStr "["
runEffect $ source >-> P.map encode >-> insertCommas
putStrLn "]"
Sign up to request clarification or add additional context in comments.

6 Comments

Great! I'm still getting used to lift and sometimes I find it hard to use it correctly.
Since Aeson's encode returns a ByteString I think I can use the intersperse function from the pipes-group package somehow? Instead of insertCommas I mean.
You can try it, but I think that intersperses a character between every pair of characters in the Bytestring.
I needed a Consumer, so I modified your code (I put it in the question). But I cannot understand why the closing ] is never outputted.
This should really be a new question. As a pipe segment insertCommas never returns, so that's why I print the brackets outside of the runEffect.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.