Сериализация значений в массив JSON с каналами

Я хотел бы сериализовать входящие значения в 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"}]

Я нашел трубку-эзон, но я не понимаю, как я должен использовать функции, которые он предоставляет.

РЕДАКТИРОВАТЬ: я изменил ответ ErikR, чтобы получить Consumer, но не выводит закрывающую скобку:

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

Я не могу понять почему.

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 "]"
Другие вопросы по тегам