我已经使用Parsec定义了一个解析器,它的Parsec Text () a
类型为a
。我还有一个“处理这个块”的功能,它将我解析的东西写入文件并且类型为a -> IO ()
。它解析的文件格式意味着我们可以合理地频繁返回“顶级”。
有没有办法把我的原始解析器“提升”到IO monad?我正在想象具有以下类型签名的东西:
liftParser :: Parsec Text () a -> (a -> IO ()) -> ParsecT Text () IO ()
其中第一个参数是纯解析器,第二个参数是“用我解析的东西做某事”功能。
显然,我可以通过在IO中重新定义我的原始解析器来合并我需要的东西,但这意味着我的单元测试看起来很糟糕,而且感觉就像是错误的方法。
另外,我不能像调用runParserT
那样疯狂,因为这会丢弃源位置信息 - 如果在输入的第1000行有错误,我想要错误消息这样说。
有没有办法做到这一点,如果是这样,怎么样?另外,这是明智的做法吗?我想我至少要设法避免累积输出数据。并且,假设我管理这样的事情,我应该期望Parsec
设法丢弃它已经处理过的输入数据吗?
正因如此,这个问题可以标记为已回答:luqui上面的评论解释了如何做到这一点。
诀窍是以多态方式定义所有解析器,类型为ParsecT Text () m
(定义都看起来像thing :: Monad m => Parsec Text () m MyType
)。然后,您可以使用m
在测试平台中实例化身份monad,并使用等于IO
的地方。