gpt4 book ai didi

parsing - Haskell/Parsec : how do I use Text. Parsec.Token with Text.Parsec.Indent(来自 indents 包)

转载 作者:行者123 更新时间:2023-12-03 14:14:16 26 4
gpt4 key购买 nike

Haskell Parsec 的 indents 包提供了一种解析缩进式语言(如 Haskell 和 Python)的方法。它重新定义了 Parser类型,那么如何使用 Parsec 的 Text.Parsec.Token 导出的 token 解析器函数模块,它们是正常的Parser类型?

背景

  • Parsec是一个解析器组合库,不管这意味着什么。
  • IndentParser 0.2.1是一个旧包,提供两个模块 Text.ParserCombinators.Parsec.IndentParser Text.ParserCombinators.Parsec.IndentParser.Token
  • indents 0.3.3是一个提供单个模块的新软件包 Text.Parsec.Indent

  • Parsec 附带 a load of modules .它们中的大多数导出了一堆有用的解析器(例如 newline 来自 Text.Parsec.Char ,它解析换行符)或解析器组合器(例如 count n p 来自 Text.Parsec.Combinator ,它运行解析器 p,n 次)

    但是,模块 Text.Parsec.Token 想要导出由用户参数化的函数以及被解析语言的特征,例如, braces p函数将在解析 '{' 和解析 '}' 之前运行解析器 p,忽略诸如注释之类的内容,其语法取决于您的语言。

    Text.Parsec.Token 的方式实现这一点的是它导出单个函数 makeTokenParser ,你调用它,给它你特定语言的参数(就像评论的样子),它返回一个记录,其中包含 Text.Parsec.Token 中的所有函数,适应您指定的语言。

    当然,在缩进风格的语言中,这些需要进一步调整(也许?这是我不确定的地方——我稍后会解释)所以我注意到 the (presumably obsolete) IndentParser package提供模块 Text.ParserCombinators.Parsec.IndentParser.Token 它看起来是 Text.Parsec.Token 的直接替代品.

    我应该在某些时候提到所有 Parsec 解析器都是一元函数,所以它们对状态做了神奇的事情,以便错误消息可以说明错误出现在源文件的哪一行和哪一列

    我的问题

    出于几个小原因,在我看来 the indents package或多或少是 IndentParser 的当前版本,但是它不提供看起来像 Text.ParserCombinators.Parsec.IndentParser.Token 的模块, 它只提供 Text.Parsec.Indent , 所以 我想知道如何从 Text.Parsec.Token 获取所有 token 解析器 (如 reserved "something" 解析保留关键字“something”,或如我之前提到的 braces)。

    在我看来,(新的) Text.Parsec.Indent通过某种单子(monad)状态魔法来计算源代码的列位是什么,因此它不需要像 whiteSpace 那样修改 token 解析器来自 Text.Parsec.Token ,这可能就是它不提供替换模块的原因。但是我遇到了类型问题。

    你看,没有 Text.Parsec.Indent ,我所有的解析器都是 Parser Something 类型Something 是返回类型, Parser是 Text.Parsec.String 中定义的类型别名
    type Parser = Parsec String ()

    但与 Text.Parsec.Indent , 而不是导入 Text.Parsec.String , 我用我自己的定义
    type Parser a = IndentParser String () a

    这使得我所有类型的解析器 IndentParser String () Something ,其中 IndentParser 在 Text.Parsec.Indent 中定义。但是我从 makeTokenParser 获得的 token 解析器在 Text.Parsec.Token是错误的类型。

    如果现在这没有多大意义,那是因为我有点迷路了。类型问题是 discussed a bit here .

    我得到的错误是我尝试替换 Parser 的一个定义上面是另一个,但是当我尝试使用 Text.Parsec.Token 中的一个 token 解析器时,我得到编译错误
    Couldn't match expected type `Control.Monad.Trans.State.Lazy.State
    Text.Parsec.Pos.SourcePos'
    with actual type `Data.Functor.Identity.Identity'
    Expected type: P.GenTokenParser
    String
    ()
    (Control.Monad.Trans.State.Lazy.State Text.Parsec.Pos.SourcePos)
    Actual type: P.TokenParser ()

    链接
  • Parsec
  • IndentParser (旧包)
  • indents ,提供Text.Parsec.Indent(新包)
  • some discussion of Parser types示例代码
  • another example of using Text.Parsec.Indent

  • 遗憾的是,上述示例都没有使用像 Text.Parsec.Token 中那样的 token 解析器。

    最佳答案

    你想做什么?

    听起来您希望在任何地方都将解析器定义为类型
    Parser Something
    (其中 Something 是返回类型)并通过隐藏和重新定义 Parser 来完成这项工作通常从 Text.Parsec.String 导入的类型或类似的。您仍然需要导入一些 Text.Parsec.String ,使 Stream 成为 monad 的实例;使用以下命令执行此操作:

    import Text.Parsec.String ()

    您对 Parser 的定义是正确的。或者等效地(对于那些在评论中关注聊天的人)您可以使用
    import Control.Monad.State
    import Text.Parsec.Pos (SourcePos)

    type Parser = ParsecT String () (State SourcePos)

    并可能取消 import Text.Parsec.Indent (IndentParser)在出现此定义的文件中。

    错误,墙上的错误

    您的问题是您正在查看编译器错误消息的错误部分。你专注于

    Couldn't match expected type `State SourcePos' with actual type `Identity'

    当你应该专注于

    Expected type: P.GenTokenParser ...
    Actual type: P.TokenParser ...

    它编译!

    Text.Parsec.Token“导入”解析器的位置, 你实际上做什么,当然(正如你简要提到的)首先定义一个记录你的语言参数,然后将它传递给函数 makeTokenParser ,它返回包含 token 解析器的记录。

    因此,您必须有一些看起来像这样的行:
    import qualified Text.Parsec.Token as P

    beetleDef :: P.LanguageDef st
    beetleDef =
    haskellStyle {
    parameters, parameters etc.
    }

    lexer :: P.TokenParser ()
    lexer = P.makeTokenParser beetleDef

    ...但是一个 P.LanguageDef st只是一个 GenLanguageDef String st Identity , 和 P.TokenParser ()真的是 GenTokenParser String () Identity .

    您必须将类型声明更改为以下内容:
    import Control.Monad.State
    import Text.Parsec.Pos (SourcePos)
    import qualified Text.Parsec.Token as P

    beetleDef :: P.GenLanguageDef String st (State SourcePos)
    beetleDef =
    haskellStyle {
    parameters, parameters etc.
    }

    lexer :: P.GenTokenParser String () (State SourcePos)
    lexer = P.makeTokenParser beetleDef

    ……就是这样!这将允许您的“导入” token 解析器具有类型 ParsecT String () (State SourcePos) Something , 而不是 Parsec String () Something (它是 ParsecT String () Identity Something 的别名),您的代码现在应该可以编译了。

    (为了最大的通用性,我假设您可能在一个文件中定义 Parser 类型,该文件与您定义实际解析器函数的文件分开并由该文件导入。因此两个重复的 import 语句。)

    谢谢

    非常感谢 Daniel Fischer帮助我解决这个问题。

    关于parsing - Haskell/Parsec : how do I use Text. Parsec.Token with Text.Parsec.Indent(来自 indents 包),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15315624/

    26 4 0
    Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
    广告合作:1813099741@qq.com 6ren.com