gaw*_*awi 61 monads haskell parsec applicative
似乎已经达成共识,你应该使用Parsec作为应用而不是monad.应用解析比monadic解析有什么好处?
monadic解析了吗?
ham*_*mar 88
monadic和applicative解析之间的主要区别在于如何处理顺序组合.在应用解析器的情况下,我们使用(<*>)
,而使用monad (>>=)
.
(<*>) :: Parser (a -> b) -> Parser a -> Parser b
(>>=) :: Parser a -> (a -> Parser b) -> Parser b
Run Code Online (Sandbox Code Playgroud)
monadic方法更灵活,因为它允许第二部分的语法依赖于第一部分的结果,但我们在实践中很少需要这种额外的灵活性.
您可能认为拥有一些额外的灵活性不会伤害,但实际上它可以.它阻止我们在不运行它的情况下对解析器进行有用的静态分析.例如,假设我们想知道解析器是否可以匹配空字符串,以及匹配中可能的第一个字符是什么.我们想要功能
empty :: Parser a -> Bool
first :: Parser a -> Set Char
Run Code Online (Sandbox Code Playgroud)
使用适用的解析器,我们可以轻松回答这个问题.(我在这里作弊一点.假设我们有对应于数据构造(<*>)
,并(>>=)
在我们的候选人分析器"语言").
empty (f <*> x) = empty f && empty x
first (f <*> x) | empty f = first f `union` first x
| otherwise = first f
Run Code Online (Sandbox Code Playgroud)
但是,使用monadic解析器,我们不知道第二部分的语法是什么,而不知道输入.
empty (x >>= f) = empty x && empty (f ???)
first (x >>= f) | empty x = first x `union` first (f ???)
| otherwise = first x
Run Code Online (Sandbox Code Playgroud)
通过允许更多,我们能够减少推理.这类似于动态和静态类型系统之间的选择.
但这有什么意义呢?我们可以使用这些额外的静态知识吗?那么,我们可以例如使用它通过下一个字符进行比较的,以避免在LL(1)解析回溯first
集合中的每个可替换的.我们还可以通过检查first
两个备选方案的集合是否重叠来静态地确定这是否是模糊的.
另一个例子是它可以用于错误恢复,如S. Doaitse Swierstra和Luc Duponcheel的文章DETministic ,Error-Correcting Combinator Parsers所示.
然而,通常应用性和一元分析之间的选择已经被你使用的解析库的作者提出.当像Parsec这样的库公开两个接口时,选择使用哪个接口纯粹是一种风格.在某些情况下,应用代码比monadic代码更容易阅读,有时候反过来也是如此.
Mat*_*hid 13
如果解析器纯粹是应用程序,则可以在运行之前分析其结构并"优化"它.如果解析器是monadic,它基本上是图灵完备程序,并且执行几乎任何有趣的分析都等同于解决暂停问题(即,不可能).
哦,是的,这也有风格差异......
Tom*_*ett 11
我可以看到更喜欢应用解析器而不是monadic解析器的主要原因与在任何上下文中优选应用代码而不是monadic代码的主要原因相同:功能较弱,应用程序使用起来更简单.
这是一个更通用的工程格言的实例:使用最简单的工具来完成工作.当小车可以使用时,不要使用叉车.不要使用台锯切出优惠券.当代码IO
纯粹时,不要编写代码.把事情简单化.
但有时,你需要额外的力量Monad
.确切的迹象是,当您需要根据到目前为止计算的内容更改计算过程时.在解析术语时,这意味着根据到目前为止已解析的内容确定如何解析接下来的内容; 换句话说,你可以用这种方式构造上下文敏感的语法.