Reh*_*que 5 parsing haskell attoparsec
我一直在编写 attoparsec 解析器,并且一直在尝试将解析器转换为递归解析器的模式(将它们与 monad bind >>= 运算符递归组合)。
所以我创建了一个函数来将解析器变成递归解析器,如下所示:
recursiveParser :: (a -> A.Parser a) -> a -> A.Parser a
recursiveParser parser a = (parser a >>= recursiveParser parser) <|> return a
Run Code Online (Sandbox Code Playgroud)
如果您有递归数据类型,这很有用
data Expression = ConsExpr Expression Expression | EmptyExpr
parseRHS :: Expression -> Parser Expression
parseRHS e = ConsExpr e <$> parseFoo
parseExpression :: Parser Expression
parseExpression = parseLHS >>= recursiveParser parseRHS
where parseLHS = parseRHS EmptyExpr
Run Code Online (Sandbox Code Playgroud)
有没有更惯用的解决方案?几乎看起来recursiveParser
应该是某种折叠......我也在sepBy
文档中看到,但这种方法似乎更适合我的应用程序。
编辑:哦,实际上现在我想到它实际上应该类似于fix
......不知道我是怎么忘记的。
EDIT2: Rotsor 用他的替代方案为我的例子提出了一个很好的观点,但恐怕我的 AST 实际上比这更复杂一点。它实际上看起来更像这个(虽然这仍然是简化的)
data Segment = Choice1 Expression
| Choice2 Expression
data Expression = ConsExpr Segment Expression
| Token String
| EmptyExpr
Run Code Online (Sandbox Code Playgroud)
其中字符串a -> b
括号在右边,c:d
括号在左边,:
绑定比->
.
即a -> b
评估为
(ConsExpr (Choice1 (Token "a")) (Token "b"))
Run Code Online (Sandbox Code Playgroud)
并c:d
评估为
(ConsExpr (Choice2 (Token "d")) (Token "c"))
Run Code Online (Sandbox Code Playgroud)
我想我可以foldl
用于一个和foldr
另一个,但那里还有更多的复杂性。请注意,这是一个稍显陌生的方式递归,所以"a:b:c -> e:f -> :g:h ->"
实际上是一个有效的字符串,但"-> a"
并"b:"
没有。最后fix
对我来说似乎更简单。我已经重命名了递归方法,如下所示:
fixParser :: (a -> A.Parser a) -> a -> A.Parser a
fixParser parser a = (parser a >>= fixParser parser) <|> pure a
Run Code Online (Sandbox Code Playgroud)
谢谢。
为什么不直接解析一个列表,然后将其折叠成您想要的任何内容呢?也许我错过了一些东西,但这对我来说看起来更自然:
consChain :: [Expression] -> Expression
consChain = foldl ConsExpr EmptyExpr
parseExpression :: Parser Expression
parseExpression = consChain <$> many1 parseFoo
Run Code Online (Sandbox Code Playgroud)
而且它也更短。
正如您所看到的,consChain
现在独立于解析,并且可以在其他地方有用。另外,如果将结果折叠分开,在这种情况下,有些不直观的递归解析会简化为many
or many1
。
您可能还想看看many
是如何实现的:
many :: (Alternative f) => f a -> f [a]
many v = many_v
where many_v = some_v <|> pure []
some_v = (:) <$> v <*> many_v
Run Code Online (Sandbox Code Playgroud)
它与您有很多共同点recursiveParser
:
some_v
类似于parser a >>= recursiveParser parser
many_v
类似于recursiveParser parser
您可能会问为什么我称您的递归解析器函数不直观。这是因为这种模式允许解析器参数影响解析行为(a -> A.Parser a
记得吗?),这可能很有用,但并不明显(我还没有看到这方面的用例)。事实上,您的示例没有使用此功能,这使它看起来多余。
归档时间: |
|
查看次数: |
1002 次 |
最近记录: |