我正在阅读关于解析器组合器的article,并且不理解以下内容:
他们说使用seq
(见下文)会导致带有嵌套元组的解析器作为结果,操作会很麻烦。
seq :: Parser a -> Parser b -> Parser (a,b)
p ‘seq‘ q = \inp -> [((v,w),inp’’) | (v,inp’) <- p inp, (w,inp’’) <- q inp’]
为了避免嵌套元组的问题,他们为解析器引入 monadic bind
和return
,然后定义seq
如下:
p ‘seq‘ q = p ‘bind‘ \x -> q ‘bind‘ \y -> result (x,y)
不幸的是,我没有看到嵌套元组的问题是什么,为什么seq
的第二个实现比第一个更好。你能帮我理解一下吗?
答案 0 :(得分:5)
第一个示例extendend到类型((a,b),(c,d,e)):
seq232 ((p,q),(r,s,t) = \inp ->
[ (((v,w),(x,y,z)),inp’’''')
| (v, inp’) <- p inp
, (w, inp’’) <- q inp’
, (x, inp''') <- r inp''
, (y, inp'''') <- s inp'''
, (z, inp''''') <- t imp''''
]
第二个例子扩展到类型((a,b),(c,d,e)):
seq232 ((p,q),(r,s,t)) =
p ‘bind‘ \v ->
q ‘bind‘ \w ->
r `bind` \x ->
s `bind` \y ->
t `bind` \z ->
result ((v,w),(x,y,z))
虽然它不是一个很多,但我认为你可以看到第二个更清洁。
答案 1 :(得分:1)
我敢说应用界面实际上比monadic界面旧。不幸的是,近年来只是越来越受到关注。
这个想法是,使用seq
组合子(不是一个幸运的名字),基本解析器返回一个&#34;简单&#34;的值。类型,然后组合成最终结果,这是一个更复杂的类型。
应用界面的想法是具有类型
的顺序组合组合器(<*>) :: Parser (b -> a) -> Parser b -> Parser a
我们首先将一个函数(具有&#34;复杂的&#34;类型)提升到一个解析器中,然后使用该解析器将后续解析器返回的参数组合成一个结果。特殊版本是&lt; *和*&gt;丢弃角支架侧面的结果。您将在Control.Applicative模块中找到此接口。
为什么要避免使用monadic解析器?由于&gt; = =组合器的右侧解析器依赖于左侧的解析器的结果,因此在解析期间反复构造该解析器。消息是:如果确实需要,只使用monadic接口,即如果你想构建依赖于解析先前运行的解析器结果的解析器。
应用解析器的示例。假设我们想要识别嵌套括号并计算最大嵌套深度。语法S - > (S)S | epsilon描述了这种结构,它直接反映在解析器中。
pS = (max . (+1)) <$ pSym '(' <*> pS <* pSym ')' <|> pure 0
monadic解析器派上用场的典型例子是例如识别^ {n} b ^ {n} c ^ {n}。我们首先要认识一些人,然后想要看到很多b&c; c和c
pAs = length <$> many(pSym 'a')
pSyms c 0 = pure 0
pSyms c n = (+1) <$ pSym c <*> pSyms c (n-1)
pABC = do count <- pAs
pSyms 'b' count
pSyms 'c' count
基本上,在do-construct的下一个语句中,正在使用早期语句的结果,而不仅仅是在最后组合它们而不在组合步骤中执行任何解析。
另见:
@inproceedings{SwieDupo96,
Author = {Swierstra, S. D. and Duponcheel, L.},
Booktitle = {Advanced Functional Programming},
Date-Added = {2009-01-04 17:21:54 +0100},
Date-Modified = {2009-01-04 17:21:54 +0100},
Editor = {Launchbury, John and Meijer, Erik and Sheard, Tim},
Pages = {184-207},
Publisher = {Springer-Verlag},
Series = {LNCS-Tutorial},
Title = {Deterministic, Error-Correcting Combinator Parsers},
Urlpdf = {http://www.cs.uu.nl/people/doaitse/Papers/1996/DetErrCorrComPars.pdf},
Volume = {1129},
Year = {1996},
}
这最终解释了为什么应该尽可能避免使用monad(就像在无上下文语法过度时你应该使用正则表达式一样)。