Reputation: 9104
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.
Upvotes: 0
Views: 413
Reputation: 52039
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 "]"
Upvotes: 1