Я определил парсер, используя Parsec, который имеет тип Parsec Text () a
для некоторых a
. У меня также есть функция "сделка с этим чанком", которая записывает в файл то, что я проанализировала, и имеет тип a -> IO ()
. Формат файла, который он анализирует, означает, что мы довольно часто возвращаемся на «верхний уровень».
Есть ли способ взять мой оригинальный парсер и "поднять его" в монаду IO? Я представляю что-то со следующей подписью типа:
liftParser :: Parsec Text () a -> (a -> IO ()) -> ParsecT Text () IO ()
где первый аргумент - чистый анализатор, а второй - функция "сделать что-то с тем, что я проанализировал".
Очевидно, что я могу собрать воедино все, что мне нужно, переопределив свой оригинальный синтаксический анализатор в IO, но это означает, что мои модульные тесты выглядят ужасно, и это выглядит как неправильный подход.
Кроме того, я не могу сделать что-то сумасшедшее, например, вызов runParserT
, потому что это приведет к удалению информации о положении источника - если в строке 1000 ввода есть ошибка, я бы хотел, чтобы в сообщении об ошибке говорилось так.
Так есть ли способ сделать это, и если да, то как? Кроме того, это разумная вещь, чтобы сделать? Я предполагаю, что мне по крайней мере удается избежать накопления выходных данных. И, предполагая, что я управляю чем-то вроде этого, я должен ожидать, что Parsec
удастся отбросить входные данные, с которыми он уже имел дело?