我正在尝试做的事情似乎很简单,但由于我是一个 parsec Haskell 新手,所以解决方案让我望而却步。
我有两个解析器,假设在哪里可以解析中间词并foo1
解析结尾词。术语用符号分隔,。foo2
foo1
foo2
"."
我需要解析的句子是
foo2
foo1.foo2
foo1.foo1.foo2
等等。
我最初的想法是做
do k <- sepBy foo1 (char'.')
j <- foo2
但这不会抓住foo2
-only 的情况。
你想要endBy
,没有sepBy
。
foo = do k <- foo1 `endBy` char '.'
j <- foo2
...
这将强制分隔符在每次出现foo1
.
当然,endBy
可以简单地替换为many
,这可能更清楚。
foo = do k <- many $ foo1 <* char '.'
j <- foo2
...
或者,没有Control.Applicative
:
foo = do k <- many $ do x <- foo1; char '.'; return x
j <- foo2
...
首先,你想要endBy
而不是sepBy
:
do k <- endBy foo1 (char'.')
j <- foo2
其次,它会
抓住刚刚的 foo2 案例
从文档中:
endBy p sep
解析零次或多次出现的p
,用 . 分隔sep
。返回由 . 返回的值的列表p
。
尝试类似的东西
many (foo1 >>= (\v -> char '.' >> return v)) >>= \v1 ->
foo2 >>= \v2 ->
-- ...
-- combine v1 & v2 somehow
(当然,只是一个草图。)
一般来说,many
组合子相当于 Parsec 的Kleene star;如果您要向现有解析器添加一些简单的东西,例如尾随点,使用>>
/>>=
实际上可能比使用do
符号更清洁和简单。
当然,它会捕获 foo2 案例。用于您的 foo1,莱顿的话:
let a = sepBy word (char '.')
parseTest a "foo.bar.baz"
parseTest a "foo"
parseTest a ".baz"