我想要做的事情看起来很简单,但由于我是一个parsec Haskell newb,解决方案就是在逃避我。
我有两个解析器,比方说foo1
和foo2
,其中foo1
可以解析一个中间词,foo2
解析一个结束词。术语以符号"."
分隔。
我需要解析的句子是
foo2
foo1.foo2
foo1.foo1.foo2
等等。
我最初的想法是
do k <- sepBy foo1 (char'.')
j <- foo2
但这不会引起foo2
- 唯一的情况。
答案 0 :(得分:3)
您需要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
...
答案 1 :(得分:2)
首先,您需要endBy
而不是sepBy
:
do k <- endBy foo1 (char'.')
j <- foo2
其次,它会
抓住刚才的foo2案例
endBy p sep
解析p
出现的{strong>零个或多个,由sep
分隔。返回p
返回的值列表。
答案 2 :(得分:0)
尝试类似
的内容many (foo1 >>= (\v -> char '.' >> return v)) >>= \v1 ->
foo2 >>= \v2 ->
-- ...
-- combine v1 & v2 somehow
(当然只是草图。)
一般来说,many
组合子是Parsec相当于Kleene star;如果你要在现有的解析器中添加一些简单的跟踪点,使用>>
/ >>=
实际上可能比使用do
表示法更简洁,更简单。
答案 3 :(得分:0)
let a = sepBy word (char '.')
parseTest a "foo.bar.baz"
parseTest a "foo"
parseTest a ".baz"