gpt4 book ai didi

parsing - Haskell/Parsec : How do you use the functions in Text. Parsec.Indent?

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

我在弄清楚如何使用 Text.Parsec.Indent 中的任何功能时遇到问题 indents 提供的模块Haskell 的包,它是 Parsec 的一种附加组件。

所有这些功能有什么作用?它们将如何使用?

我能理解 withBlock 的简短黑线鳕描述,并且我找到了如何使用 withBlock 的示例, runIndentIndentParser类型 here , herehere .我也能看懂四个解析器的文档 indentBrackets and friends .但是很多事情仍然让我感到困惑。

特别是:

  • withBlock f a p有什么区别和
    do aa <- a
    pp <- block p
    return f aa pp

    同样,withBlock' a p 和有什么区别?和 do {a; block p}
  • 在函数族中 indented and friends ,什么是“引用水平”?也就是说,什么是“引用”?
  • 同样,使用函数 indented friend 们,如何使用呢?除了 withPos ,看起来它们没有参数并且都是 IParser () 类型(IParser 定义为 thisthis )所以我猜他们所能做的就是是否产生错误,并且它们应该出现在 do 中块,但我无法弄清楚细节。

    我至少找到了一些关于 withPos 用法的例子。在 source code ,所以如果我盯着它看的时间足够长,我可能会弄清楚。
  • <+/> 附带有用的说明“<+/>缩进敏感解析器是什么ap is to monads”,如果你想花几个时间来尝试围绕你的头脑,这很好ap然后找出它与解析器的相似之处。其他 three combinators然后引用 <+/> 定义,使整个团队对新人来说难以接近。

    我需要使用这些吗?我可以忽略它们并使用 do反而?
  • 普通 lexeme 组合器和 whiteSpace Parsec 的解析器会很高兴地在多 token 构造中间消耗换行符,而不会提示。但是在缩进风格的语言中,有时你想停止解析词法结构或在一行被破坏并且下一行缩进少于它应该的时候抛出一个错误。我如何在 Parsec 中做到这一点?
  • language我正在尝试解析,理想情况下,允许词汇结构继续到下一行的规则应该取决于出现在第一行末尾或后续行开头的标记。有没有一种简单的方法可以在 Parsec 中实现这一目标? (如果很难,那么我现在不需要关心它。)
  • 最佳答案

    所以,第一个提示是看看IndentParser

    type IndentParser s u a = ParsecT s u (State SourcePos) a

    IE。这是一个 ParsecT密切关注 SourcePos ,一个抽象容器,可用于访问当前列号等。因此,它可能将当前的“缩进级别”存储在 SourcePos 中。 .这将是我对“引用水平”意味着什么的初步猜测。

    总之, indents给你一种全新的 Parsec这是上下文敏感的——特别是对当前缩进敏感。我会乱序回答你的问题。

    (2) “引用级别”是在此缩进级别开始的当前解析器上下文状态中引用的“信念”。为了更清楚,让我给出一些关于(3)的测试用例。

    (3) 为了开始试验这些函数,我们将构建一个小测试运行器。它将使用我们提供的字符串运行解析器,然后解开内部 State部分使用 initialPos我们可以修改。在代码中
    import Text.Parsec
    import Text.Parsec.Pos
    import Text.Parsec.Indent
    import Control.Monad.State

    testParse :: (SourcePos -> SourcePos)
    -> IndentParser String () a
    -> String -> Either ParseError a
    testParse f p src = fst $ flip runState (f $ initialPos "") $ runParserT p () "" src

    (注意,这几乎是 runIndent ,除了我给了一个后门来修改 initialPos 。)

    现在我们可以看看 indented .通过检查来源,我可以看出它有两件事。首先,它会 fail如果当前 SourcePos列号小于或等于 SourcePos 中存储的“引用级别”存储在 State .其次,它有点神秘地更新了 State SourcePos的行计数器(不是列计数器)是当前的。

    据我所知,只有第一个行为很重要。我们可以在这里看到不同之处。
    >>> testParse id indented ""
    Left (line 1, column 1): not indented

    >>> testParse id (spaces >> indented) " "
    Right ()

    >>> testParse id (many (char 'x') >> indented) "xxxx"
    Right ()

    所以,为了拥有 indented成功,我们需要消耗足够的空白(或其他任何东西!)以将我们的列位置推出超过“引用”列位置。否则,它将无法说“未缩进”。接下来的三个函数存在类似的行为: same除非当前位置和引用位置在同一条线上,否则失败, sameOrIndented如果当前列严格小于引用列,则失败,除非它们在同一行,并且 checkIndent除非当前列和引用列匹配,否则失败。
    withPos略有不同。这不仅仅是一个 IndentParser ,这是一个 IndentParser -combinator——它转换输入 IndentParser认为“引用列”( SourcePos 中的 State )正是我们调用时的位置 withPos .

    这给了我们另一个提示,顺便说一句。它让我们知道我们有权更改引用列。

    (1) 那么现在让我们来看看 blockwithBlock使用我们新的、较低级别的引用列运算符工作。 withBlock根据 block 实现,所以我们将从 block 开始.
    -- simplified from the actual source
    block p = withPos $ many1 (checkIndent >> p)

    所以, block将“引用列”重置为当前列的任何内容,然后从 p 消耗至少 1 次解析只要每一个都与这个新设置的“引用列”的缩进相同。现在我们可以看看 withBlock
    withBlock f a p = withPos $ do
    r1 <- a
    r2 <- option [] (indented >> block p)
    return (f r1 r2)

    因此,它将“引用列”重置为当前列,解析单个 a解析,尝试解析 indented blockp s,然后使用 f 组合结果.您的实现几乎是正确的,只是您需要使用 withPos选择正确的“引用栏”。

    然后,一旦你有了 withBlock , withBlock' = withBlock (\_ bs -> bs) .

    (5) 所以, indented和 friend 正是这样做的工具:如果相对于 withPos 选择的“引用位置”缩进不正确,它们将导致解析立即失败。 .

    (4) 是的,在您学会如何使用 Applicative style 之前不要担心这些家伙。解析基数 Parsec .它通常是一种更清晰、更快、更简单的指定解析的方法。有时它们甚至更强大,但如果您了解 Monad s 那么它们几乎总是完全等价的。

    (6) 这就是症结所在。到目前为止提到的工具只有在您可以使用 withPos 描述您想要的缩进时才会导致缩进失败。 .很快,我认为不可能指定 withPos基于其他解析的成功或失败......所以你必须更深入另一个层次。幸运的是,机制使得 IndentParser的工作是显而易见的——它只是一个内在的 State单子(monad)包含 SourcePos .您可以使用 lift :: MonadTrans t => m a -> t m a操纵这个内部状态并设置“引用列”,但是你喜欢。

    干杯!

    关于parsing - Haskell/Parsec : How do you use the functions in Text. Parsec.Indent?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15549050/

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