openBr = char '['
closeBr = char ']'
openPn = char '('
closePn = char ')'
star = char '*'
myParser =
(many1 star >>=
\vs -> myParser >>=
\x -> return (x+length vs)
) +++
(openBr >>
myParser >>=
\c -> closeBr >>
myParser >>=
\d -> return (c+d)
) +++
(openPn >>
myParser >>=
\c -> closePn >>
myParser >>=
\d -> return (c+d)
) +++
return 0parse myParser "*(***[*(**)]*)*"
-- outputs ([9,""])
parse myParser "*(***[*(**]*)*"
-- outputs ([1, "(***[*(**]*)*"])当有一个匹配的括号和括号时,它会返回星星的数量,但是它会像第二个输出一样返回。我不明白代码是怎么工作的。有人能给我解释一下吗?
发布于 2021-12-07 21:58:52
首先,在编写这样的一元Haskell代码时,使用do notation是惯用的。这样可以减少噪音,使你的意图更清晰。
使用do符号重写的解析器如下所示:
myParser =
-- run of stars
(do
vs <- many1 star
x <- myParser
return (x+length vs)
) +++
-- brackets
(do
openBr
c <- myParser
closeBr
d <- myParser
return (c+d)
) +++
-- parentheses
(do
openPn
c <- myParser
closePn
d <- myParser
return (c+d)
) +++
-- fail
return 0现在,当您解析第二个示例时,解析器将正确地解析第一个星号,并将总数增加到1,然后它会看到打开的括号,因此它选择了括号选择。
但是括号是不平衡的,因此括号解析器失败了,尽管它能够解析开括号后面的一些字符。这会导致泡沫上升的失败和整体解析的失败。当发生这种情况时,parse函数返回迄今累积的返回值,即故障前的星数,以及未解析的字符串的其余部分。
在这种情况下,您想要做的是使解析失败并返回0。因为解析库不会自动回溯,所以需要通过将子解析器封装在类库的等效try组合器中,显式地启用回溯。
哈斯克林快乐!
https://stackoverflow.com/questions/70253355
复制相似问题