Сериализация значений в массив 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"}]

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

ИЗМЕНИТЬ: я изменил ответ ErikR, чтобы получить Consumer, но закрывающая скобка не выводится:

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

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


person rubik    schedule 01.11.2015    source источник


Ответы (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 "]"
person ErikR    schedule 01.11.2015
comment
Большой! Я все еще привыкаю к ​​lift и иногда мне трудно использовать его правильно. - person rubik; 01.11.2015
comment
Поскольку encode Aeson возвращает ByteString, я думаю, что могу использовать _ 2_ как-то из пакета pipe-group? Я имею в виду, вместо insertCommas. - person rubik; 01.11.2015
comment
Вы можете попробовать это, но я думаю, что это перемежает символ между каждой парой символов в Bytestring. - person ErikR; 01.11.2015
comment
Мне нужен был Consumer, поэтому я изменил ваш код (я поставил его в вопросе). Но я не могу понять, почему закрывающий ] никогда не выводится. - person rubik; 01.11.2015
comment
Это действительно должен быть новый вопрос. Поскольку сегмент трубы insertCommas никогда не возвращается, поэтому я печатаю скобки вне runEffect. - person ErikR; 01.11.2015
comment
Вы правы, вопрос немного сложнее. Я задал это в новом вопросе здесь: stackoverflow.com/questions/33464543/ Спасибо за терпение и помощь. - person rubik; 01.11.2015