Parsec vs Yacc/Bison/Antlr:为什么以及何时使用Parsec?

Nin*_*ang 42 haskell parsec

我是Haskell和Parsec的新手.在阅读了第16章使用真实世界Haskell的Parsec之后,我脑子里出现了一个问题:为什么以及何时Parsec比Yacc/Bison/Antlr等其他解析器生成器更好?

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

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

顺便说一句:我的问题与这个问题非常相似,但在那里没有得到令人满意的回答.

Jör*_*tag 56

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

解析器生成器读入语法描述并吐出解析器.通常不可能现有的语法组合成新的语法,并且当然不可能将两个现有的生成的解析器组合成新的解析器.

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

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

大多数解析器生成器不支持此功能,或仅以有限的方式支持它.解析器组合器 OTOH 支持此而不是其他任何东西.

  • @sclv:谢谢.我想我已经修复了所有我实际上在讨论图书馆整体的实例,并将那些实际情况与实际谈论单个组合器的实例区分开来.我非常感谢你的评论,因为我一般都是正确术语的坚持者.有趣的是,Parsec的大多数Ruby和Smalltalk端口组合了解析器对象,而不是解析器函数,尽管当然函数只是一个只有一个方法的对象,而一个对象只是一个(记录)函数,部分应用于`this` :-) (3认同)
  • s/combinator/combinator库.从经典的角度来说,组合器是一个函数,它接受函数并返回函数.组合器库是一个由大多数组合器功能构建的库. (2认同)

ste*_*ley 9

您可能希望在问题中看到此问题以及链接的问题.

哪种Haskell解析技术最令人愉快,为什么?

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

对于行业惯例,决定使用Haskell来获得Parsec会很奇怪.对于解析,大多数当前语言将至少具有解析器生成器,并且可能像Parsec端口或PEG系统那样更灵活.

艾拉·巴克斯特对这个相关问题的回答是关于一个解析器让你只是为了编写一个翻译器而得到喜马拉雅山的立足点,但是作为翻译器的一部分只是解析器的一个用途,因此仍有许多领域其中像ANTLR,Happy和Parsec这样极简主义的系统令人满意.


chr*_*sdb 6

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

  • @John F. Miller我不确定Attoparsec的解析器是否曾经不是monad,但现在肯定不是这样,我非常怀疑它是不是这样.Parsec和Attoparsec都鼓励在可能的情况下使用Applicative而不是monad ...但实际上我只是检查了Hackage的最旧版本,从2008年开始,就在你的帖子发布前5年,将它作为Monad.所以这只是简单的错误信息. (5认同)