难以让Parsec解析器正确跳过空格

Nei*_*ter 6 haskell parsec

我是Parsec的新手(以及一般的解析器),我写的这个解析器遇到了一些麻烦:

list = char '(' *> many (spaces *> some letter) <* spaces <* char ')'
Run Code Online (Sandbox Code Playgroud)

我的想法是以这种格式解析列表(我正在研究s表达式):

(firstElement secondElement thirdElement and so on)
Run Code Online (Sandbox Code Playgroud)

我写了这段代码来测试它:

import Control.Applicative
import Text.ParserCombinators.Parsec hiding (many)

list = char '(' *> many (spaces *> some letter) <* spaces <* char ')'

test s = do
  putStrLn $ "Testing " ++ show s ++ ":"
  parseTest list s
  putStrLn ""

main = do
  test "()"
  test "(hello)"
  test "(hello world)"
  test "( hello world)"
  test "(hello world )"
  test "( )"
Run Code Online (Sandbox Code Playgroud)

这是我得到的输出:

Testing "()":
[]

Testing "(hello)":
["hello"]

Testing "(hello world)":
["hello","world"]

Testing "( hello world)":
["hello","world"]

Testing "(hello world )":
parse error at (line 1, column 14):
unexpected ")"
expecting space or letter

Testing "( )":
parse error at (line 1, column 3):
unexpected ")"
expecting space or letter
Run Code Online (Sandbox Code Playgroud)

如您所见,当列表的最后一个元素与结束之间存在空白时,它会失败).我不明白为什么spaces我刚放入的白色空间没有消耗掉<* char ')'.我犯了什么愚蠢的错误?

Dan*_*her 12

问题是最终的空间是由spaces参数中的many,

list = char '(' *> many (spaces *> some letter) <* spaces <* char ')'
                     --  ^^^^^^ that one
Run Code Online (Sandbox Code Playgroud)

然后解析器期望some letter但找到一个右括号因此失败.

要解决它,只令牌之后消耗空间,

list = char '(' *> spaces *> many (some letter <* spaces) <* char ')'
Run Code Online (Sandbox Code Playgroud)

按预期工作:

$ runghc lisplists.hs 
Testing "()":
[]

Testing "(hello)":
["hello"]

Testing "(hello world)":
["hello","world"]

Testing "( hello world)":
["hello","world"]

Testing "(hello world )":
["hello","world"]

Testing "( )":
[]
Run Code Online (Sandbox Code Playgroud)