Parsec与Yacc/Bison/Antlr:何时何地使用Parsec? (注:此为提问标题,无需回答)

44
我对Haskell和Parsec都很陌生。在阅读了Real World Haskell的第16章使用Parsec之后,我有一个问题:为什么和何时使用Parsec比其他解析器生成器(如Yacc/Bison/Antlr)更好?
我的理解是,Parsec创建了一种很好的编写解析器的DSL,并且Haskell使其非常易于表达。但解析是一种如此标准/流行的技术,值得拥有自己的语言,可以输出到多个目标语言。那么我们应该在什么情况下使用Parsec,而不是从Bison/Antlr生成Haskell代码呢?
这个问题可能超出了技术范畴,涉及到行业实践。从零开始编写解析器时,与选择Bison/Antlr或类似工具相比,选择Haskell/Parsec的好处是什么?
顺便说一句:我的问题与这个问题非常相似,但那里的答案并不令人满意。

8
“解析是一种标准/流行的技术,值得拥有自己的语言,可以输出到多种目标语言。” 我很想知道为什么这样说——我对这个主题了解得不够深入,无法完全同意或反对,但它肯定不是一个不言自明的陈述。 - Antal Spector-Zabusky
3个回答

57
你列出的工具之间的主要区别之一是,ANTLR、Bison等工具是解析器生成器,而Parsec是一个解析器组合库。
解析器生成器会读取语法描述,并生成一个解析器。通常情况下,无法将现有的语法组合成新的语法,也绝不能将两个现有的生成解析器组合成新的解析器。
相反,解析器组合器只会将现有解析器组合成新解析器。通常情况下,解析器组合库附带几个可以解析空字符串或单个字符的基本内置解析器,并附带一组组合器,这些组合器接受1个或多个解析器,并返回一个新的解析器,例如解析原始解析器序列(例如,您可以将"d"解析器和"o"解析器组合成一个"do"解析器)、交替解析原始解析器(例如,一个"0"解析器和一个"1"解析器组合成一个"0|1"解析器)或多次解析原始解析器(重复)。
这意味着,您可以将现有的Java解析器和现有的HTML解析器组合成用于解析JSP的解析器。
大多数解析器生成器不支持此功能,或仅以有限的方式支持。而解析器组合器则只支持此功能,而不支持其他功能。

2
将“s / combinator / combinator library”进行翻译。经典意义上,组合子是一个接受函数并返回函数的函数。组合子库是由大部分组合子函数构建的库。 - sclv
3
@sclv:谢谢。我想我已经修复了所有实际上是在谈论整个库的情况,并留下了那些实际上是在谈论单个组合器的情况。我非常感激您的评论,因为我通常会严格遵守正确的术语。有趣的是,大多数Ruby和Smalltalk版本的Parsec都组合解析器对象,而不是解析器函数,尽管当然,函数只是具有一个方法的对象,而对象只是部分应用到this的函数(记录)。 :-) - Jörg W Mittag

9

您可能也想看一下您问题中链接的这个问题。

哪个Haskell解析技术最易用,为什么?

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

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

与链接问题的Ira Baxter的答案非常准确,指出解析器仅仅是编写翻译器的入门基础,但成为翻译器的一部分只是解析器的许多用途之一,因此仍然有许多领域可以使用相当简约的系统,如ANTLR,Happy和Parsec。


6

继stephen的回答之后,如果你想坚持使用解析器组合器,我认为最常见的替代Parsec的方法之一是attoparsec。主要区别在于,attoparsec更加偏重于速度,并相应地进行了折衷。例如,Parsec会进行一些簿记以尝试返回有用的错误消息(如果解析失败),而attoparsec并不完全这样做。此外,我认为attoparsec专门针对一种输入流/令牌类型进行了优化,而Parsec从输入类型中抽象出来,因此可以轻松解析String、ByteString、Text等类型的流。


1
attoparsec的解析器也是一个applicative functor,但重要的是它不是一个monad。这意味着使用applicative组合子(<*> <|> <$>)而不是do记号或monad函数。 - John F. Miller
7
我不确定 Attoparsec 的解析器曾经是否不是一个 Monad,但现在肯定不是了,而且我非常怀疑它曾经是这样。无论是 Parsec 还是 Attoparsec,在可能的情况下都鼓励使用 Applicative 而不是 Monad。实际上,我刚刚检查了 Hackage 上最旧的版本,来自 2008 年,比您的帖子早了 5 年,它将其作为一个 Monad。因此,那是纯粹不正确的信息。 - alternative

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接