我正在尝试做的事情似乎很简单,但由于我是一个 parsec Haskell 新手,所以解决方案让我望而却步。
我有两个解析器,假设在哪里可以解析中间词并foo1解析结尾词。术语用符号分隔,。foo2foo1foo2"."
我需要解析的句子是
foo2foo1.foo2foo1.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"