haskell - 如何将 Megaparsec 与 Text.Read (派生的 Read 实例)结合使用
问题描述
我想在 megaparsec 模块中使用 Read 的派生实例。如何在 'Parser a' 中使用 'Text.Read.read' 或 'Text.Read.readEither' ?
它不需要快速,但易于维护和扩展。megaparsec 模块用于通过 CLI 测试我的应用程序,因此必须解析许多不同的数据类型。
它应按以下方式工作:
import Text.Megaparsec
readableDatatype :: Read a => Parser a
readableDatatype =
-- This is wrong, but describes how it shall work
-- liftA read chunkToTokens
expr' :: Parser UserControlExpr
expr' = timeExpr
<|> timeEventExpr
<|> digiInExpr
<|> quitExpr
digiInExpr :: Parser UserControlExpr
digiInExpr = do
cmdword "digiIn"
inElement <- (readableDatatype :: Parser TI_I)
return $ UserDigiIn inElement
我必须写什么,以便三个函数类型检查,尤其是readableDataype
?
解决方案
您可以为此使用getInput :: MonadParsec e s m => m s
and 。并且只需获取和设置解析器正在处理的输入流并获取一个字符串并返回一个可能的解析列表以及输入的剩余未使用部分。我们还需要告诉解析器输入中的新偏移量,否则错误位置是错误的。我们可以使用and来做到这一点。setInput :: MonadParsec e s m => s -> m ()
reads :: Read a => String -> [(a, String)]
getInput
setInput
reads
getOffset
setOffset
-- For equality constraint (~)
{-# LANGUAGE TypeFamilies #-}
import Text.Megaparsec
import Text.Read (reads)
readableDatatype :: (Read a, MonadParsec e s m, s ~ String) => m a
readableDatatype = do
input <- getInput
offset <- getOffset
choice $
(\(a, input') -> a <$ setInput input'
<* setOffset (offset + length input - length input'))
<$> reads input
如果您的输入不是其他String
内容,则必须在 that 和String
aftergetInput
和 before之间进行转换setInput
。
以下是关于性能问题,因此与您的问题并不真正相关,但它可能具有教育意义,并且可能对可能需要具有良好性能的解决方案的其他人有用。
String
在解析过程中一直在和其他类型之间转换整个输入是较大输入的一个相当大的性能瓶颈。此外length
,在这里计算新的偏移量也不是很高效。
为了解决这两个问题,需要某种方法能够知道 Read-parser 实际消耗了多少输入,这样我们就可以从原始输入中删除该部分,而不必将整个未消耗的部分转换回来到原始输入类型。但是Read
班级没有那个。可以尝试逐步解析输入的更长前缀,这在使用完成的解析Read
比整个输入的长度短的情况下可能更快。您还可以使用unsafePerformIO
写入IORef
读取解析器实际强制执行多少输入,这将是最快但不是那么漂亮的解决方案。
我在这里实现了后者。随意使用它,但请注意它没有经过很好的测试。然而,它确实解决了上述方法的所有问题。
推荐阅读
- python - 如何在不打开大型csv文件的情况下读取每行的数字总和
- libvlc - 如何在 libvlc sharp 3.4.0 中更改字幕的字体和大小?
- android - 添加 TextInputLayout 后可能导致 ClassCastException 的原因
- django - Django Fullcalendar - 应用程序中的多个日历
- javascript - document.cookie 设置了错误的路径
- scikit-learn - scikit 学习不需要的并行处理
- c# - 如何在c#中将缩写“IST”转换为“印度标准时间”
- powershell - 远程电脑的测试连接
- ios - UIStackView 对齐问题
- java - 如何在 onCreate Java 生命周期中调用视图方法?