我想在megaparsec模块中使用Read的派生实例。如何在“解析器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?
发布于 2019-01-28 02:02:33
为此,您可以将getInput :: MonadParsec e s m => m s和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,则必须在getInput之后和setInput之前在它和String之间进行转换。
以下是关于性能的问题,所以与您的问题不太相关,但可能具有教育意义,可能对需要性能良好的解决方案的其他人有用。
对于较大的输入,在解析期间一直在String和其他类型之间转换整个输入是一个相当大的性能瓶颈。此外,在这里使用length计算新的偏移量也不是很好。
要解决这两个问题,需要某种方法能够知道读取解析器实际消耗了多少输入,这样我们就可以从原始输入中删除该部分,而不必将整个未使用的部分转换回原始输入类型。但是Read类没有这样的功能。可以尝试逐步解析输入的较长前缀,如果使用Read完成的解析与整个输入的长度相比较短,则可能会更快。您还可以使用unsafePerformIO向IORef写入多少输入实际上是由读取解析器强制执行的,这将是最快但不太美观的解决方案。
我实现了后一个here。你可以随意使用它,但要知道它并没有经过很好的测试。然而,它确实解决了上述方法的所有问题。
发布于 2019-01-29 07:01:27
这就完成了。谢谢!同时,我对这个问题做了一个“保守”的解决方案,将构造函数定义为字符串并对其进行解析,而不使用read。这有一个好处,那就是你得到了令人印象深刻的兆秒错误信息,它告诉你丢失了什么符号。
使用read的示例
1:8:
|
1 | digiIn TI_I_Signal1 DirA Dectivated
| ^
unknown parse error(“停用”中只缺了一个'a‘)
使用数据类型的手写解析器的示例:
1:19:
|
1 | digiIn TI_I_Signal1 Dectivated
| ^^^^^^^^
unexpected "Dectivat"
expecting "active", "inactive", '0', or '1'我想我会在将来的数据类型中使用你的代码块。非常感谢!
https://stackoverflow.com/questions/54384656
复制相似问题