Dav*_*vid 6 parsing haskell parsec
使用Parsec,我能够String -> Maybe MyType
相对轻松地编写一个类型的函数.我现在想Read
基于它为我的类型创建一个实例; 但是,我不明白readsPrec
它是如何工作的或它应该做什么.
我现在最好的猜测readsPrec
是用于从头开始构建一个递归解析器来遍历一个字符串,在Haskell中构建所需的数据类型.但是,我已经拥有一个非常强大的解析器,它为我做了那件事.那么如何告诉readsPrec
我使用我的解析器呢?什么是"运算符优先级"参数,它在我的上下文中有什么用?
如果它有帮助,我在Github上创建了一个最小的例子.它包含一个类型,一个解析器和一个空白的Read实例,并且很好地反映了我被卡住的地方.
(背景:真正的解析器用于Scheme.)
然而,我已经有了一个非常强大的解析器,它可以为我做这件事。
它实际上不是那么健壮,你的解析器有多余括号的问题,它不会解析
((1) (2))
Run Code Online (Sandbox Code Playgroud)
例如,它会在某些格式错误的输入上引发异常,因为
singleP = Single . read <$> many digit
Run Code Online (Sandbox Code Playgroud)
可以使用read "" :: Int
.
顺便说一下,优先级参数用于确定在某些地方是否需要括号,例如,如果您有
infixr 6 :+:
data a :+: b = a :+: b
data C = C Int
data D = D C
Run Code Online (Sandbox Code Playgroud)
您不需要将 a 括起来C 12
作为 的参数(:+:)
,因为 application 的优先级高于 的优先级(:+:)
,但您需要将括号括起来C 12
作为 的参数D
。
所以你通常会有类似的东西
readsPrec p = needsParens (p >= precedenceLevel) someParser
Run Code Online (Sandbox Code Playgroud)
wheresomeParser
解析输入中的值而不用括号括起来,并needsParens True thing
解析括号之间的 a thing
,同时解析可选地needsParens False thing
括在括号中的a [您应该始终接受比必要的更多的括号,应该将其解析为]。thing
((((((1))))))
Int
由于readsPrec p
解析器用于在读取列表、元组等时将部分输入解析为值的一部分,因此它们不仅必须返回解析后的值,还必须返回输入的其余部分。
这样,将parsec
解析器转换为readsPrec
解析器的简单方法是
withRemaining :: Parser a -> Parser (a, String)
withRemaining p = (,) <$> p <*> getInput
parsecToReadsPrec :: Parser a -> Int -> ReadS a
parsecToReadsPrec parsecParser prec input
= case parse (withremaining $ needsParens (prec >= threshold) parsecParser) "" input of
Left _ -> []
Right result -> [result]
Run Code Online (Sandbox Code Playgroud)
如果您使用 GHC,那么最好使用ReadPrec / ReadP
解析器(使用 构建Text.ParserCombinators.ReadP[rec]
)而不是parsec
解析器并使用 DefinereadPrec
代替readsPrec
。