【问题标题】:Parsec vs Yacc/Bison/Antlr: Why and when to use Parsec?Parsec vs Yacc/Bison/Antlr:为什么以及何时使用 Parsec?
【发布时间】:2011-02-20 05:11:34
【问题描述】:

我是 Haskell 和 Parsec 的新手。看完Chapter 16 Using Parsec of Real World Haskell,我的脑海里出现了一个问题:Parsec 为什么和什么时候比其他解析器生成器比如 Yacc/Bison/Antlr 更好?

我的理解是 Parsec 创建了一个很好的编写解析器的 DSL,而 Haskell 使它变得非常简单和富有表现力。但是解析是一种标准/流行的技术,值得拥有自己的语言,可以输出到多种目标语言。那么我们什么时候应该使用 Parsec 而不是从 Bison/Antlr 生成 Haskell 代码?

这个问题可能会超越技术,进入行业实践领域。从头开始编写解析器时,与 Bison/Antlr 或类似的东西相比,使用 Haskell/Parsec 有什么好处?

顺便说一句:我的问题与this one 非常相似,但没有得到令人满意的回答。

【问题讨论】:

  • “但是解析是一种标准/流行的技术,值得拥有自己的语言,它可以输出多种目标语言。”我很想知道为什么——我对这个主题了解得不够多,无法真正同意或不同意,但它肯定不会让我觉得这是一个不言而喻的陈述。

标签: haskell parsec


【解决方案1】:

您列出的工具之间的主要区别之一是 ANTLR、Bison 和它们的朋友是解析器生成器,而 Parsec 是解析器组合器库。 p>

解析器生成器读取语法描述并输出解析器。将现有的语法组合到一个新的语法中通常是不可能的,当然也不可能将两个现有的生成的解析器组合成一个新的解析器。

解析器组合器OTOH什么都不做但是将现有的解析器组合成新的解析器。通常,解析器组合器库附带几个可以解析空字符串或单个字符的简单内置解析器,并且它附带一组组合器,它们采用一个或多个解析器并返回一个新的解析器,例如, 解析原始解析器的序列(例如,您可以将d 解析器和o 解析器组合成do 解析器),原始解析器的交替(例如0 解析器和@987654325 @parser 到 0|1 解析器)或多次解析原始解析(重复)。

这意味着,例如,您可以使用现有的 Java 解析器和现有的 HTML 解析器,并将它们组合成 JSP 解析器。

大多数解析器生成器不支持此功能,或者仅以有限的方式支持它。解析器组合器 OTOH 支持此功能,不支持其他功能。

【讨论】:

  • s/combinator/combinator 库。组合器,经典地说,是一个接受函数并返回函数的函数。组合子库是一个由组合子函数构建的库。
  • @sclv:谢谢。我想我修复了我实际上谈论整个库的所有实例,并留下了我实际谈论单个组合器的那些实例。我非常感谢您的评论,因为我通常坚持正确的术语。有趣的是,Parsec 的大多数 Ruby 和 Smalltalk 端口都结合了解析器对象,而不是解析器函数,尽管函数当然只是一个只有一个方法的对象,而一个对象只是部分应用于 this 的函数(记录) :-)
【解决方案2】:

您可能希望查看此问题以及问题中的链接问题。

Which Haskell parsing technology is most pleasant to use, and why?

在 Haskell 中,Parsec(和其他解析器组合器)和解析器生成器 Happy 之间存在竞争。如果我已经有一个 LR 语法可以使用,我会选择 Happy - 解析器组合器采用 LL 形式的语法,从 LR 到 LL 的翻译需要一些努力,而组合器解析器通常会慢得多。如果我没有语法,我将使用 Parsec,它比 Happy 更灵活(强大),并且在“在 Haskell 中”工作比使用 Happy 和 Alex 生成代码更有趣。如果您使用 Happy 进行解析,您几乎总是需要使用 Alex 进行词法分析。

对于行业实践,决定使用 Haskell 只是为了获得 Parsec 是很奇怪的。对于解析,目前大多数语言都至少有一个解析器生成器,可能还有更灵活的东西,比如 Parsec 端口或 PEG 系统。

Ira Baxter 对相关问题的回答恰如其分地指出了一个解析器让你仅仅为了编写一个翻译器而让你到达喜马拉雅山的立足点,但成为翻译器的一部分只是其中一个用途对于解析器,仍然有许多领域可以满足像 ANTLR、Happy 和 Parsec 这样的极简系统。

【讨论】:

    【解决方案3】:

    继斯蒂芬的回答之后,我认为如果您想坚持使用解析器组合器,最常见的 Parsec 替代方案之一是 attoparsec。主要区别在于 attoparsec 的编写更偏向于速度,并相应地进行权衡。例如,如果解析失败,Parsec 会进行一些记账以尝试返回有用的错误消息,而 attoparsec 不会在相同程度上做到这一点。另外,我认为 attoparsec 专门针对一种输入流/令牌类型,而 Parsec 从输入类型中抽象出来,以便它可以毫无问题地解析 String、ByteString、Text 等类型的流。

    【讨论】:

    • attoparsec 的解析器也是一个应用函子,但重要的是不是一个单子。这意味着使用一组应用组合符 ( ) 而不是 do 表示法或 monad 函数。
    • @John F. Miller 我不确定是否曾经有过 Attoparsec 的解析器不是 monad,但现在肯定不是这样,我非常怀疑它曾经是案子。 Parsec 和 Attoparsec 都鼓励在可能的情况下使用 Applicative 的 over monad,不过……实际上,我刚刚检查过 Hackage 上最旧的版本,从 2008 年开始,在你的帖子之前 5 年,它是一个 Monad。所以这只是简单的错误信息。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多