parsing - 使用 Parsec 写入 Read 实例

标签 parsing haskell parsec

使用 Parsec,我可以相对轻松地编写 String -> Maybe MyType 类型的函数。我现在想基于此为我的类型创建一个 Read 实例;但是,我不明白 readsPrec 是如何工作的或者它应该做什么。

我现在最好的猜测是,readsPrec 用于从头开始构建递归解析器来遍历字符串,在 Haskell 中构建所需的数据类型。然而,我已经有了一个非常强大的解析器,它可以为我做这件事。那么我如何告诉 readsPrec 使用我的解析器呢?它采用的“运算符优先级”参数是什么?它在我的上下文中有何用处?

如果有帮助,我创建了一个 minimal example on Github 。它包含一个类型、一个解析器和一个空白 Read 实例,并且很好地反射(reflect)了我陷入困境的地方。

(背景:真正的解析器是针对Scheme的。)

最佳答案

However, I already have a very robust parser who does that very thing for me.

它实际上不是那么健壮,你的解析器有多余括号的问题,它不会解析

((1) (2))

例如,它会在某些格式错误的输入上引发异常,因为

singleP = Single . read <$> many digit

可以使用读取“”::Int

顺便说一句,优先级参数用于确定在某些地方是否需要括号,例如如果你有

infixr 6 :+:

data a :+: b = a :+: b

data C = C Int

data D = D C

您不需要将 C 12 括起来作为 (:+:) 的参数,因为 application 的优先级高于 (:+:),但您需要将 C 12 括起来作为 D 的参数。

所以你通常会有类似的东西

readsPrec p = needsParens (p >= precedenceLevel) someParser

其中 someParser 解析输入中的值而不用括号括起来,而 needsParens True thing 解析括号之间的 thing,而 needParens False 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]

如果您使用的是 GHC,则最好使用 ReadPrec/ReadP 解析器(使用 Text.ParserCombinators.ReadP[rec] 构建)而不是parsec 解析器并定义 readPrec 而不是 readsPrec

关于parsing - 使用 Parsec 写入 Read 实例,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14523728/

相关文章:

regex - 插入式、可移植的解析

c# - Sprache:语法中的左递归

c# - 读取大型文本文件(超过 400 万行)并在 .NET 中解析每一行

haskell - 在 Haskell 中处理大文件

parsing - 无法计算解析器的最小长度 - Haskell 中的 uu-parsinglib

haskell - Parsec 和自定义解析错误类型

haskell - 如何使 Parsec chainl1 函数遵循运算符优先级规则

c - 如何从字节可寻址数组中解析出 n 位元素

Haskell 类型错误 : Inferred type is less polymorphic than expected

haskell - 为什么在 GHC 7.10 中进行类型检查的代码不再在 GHC 8.0.1 中进行类型检查?