Parsec:解析列表列表,两者都具有相同的分隔符

Parsec: Parsing a list of lists, both with the same delimiter

考虑一种简单的语言,它是 space 分隔命令的列表。每个命令都以一个字母作为命令名称,并以一系列 space 分隔的数字作为其参数;例如a 1 2 3 b 4 5 6 d 7 e f 将代表以下命令:

问题是它一直在 sepBy 抓取物品,然后伸手去拿另一个号码,但当它到达 "b" 时失败了。

但是,当通过下面的代码传递时会产生以下错误:

Left "error" (line 1, column 5):
unexpected "b"
expecting space

我现在意识到这可能是因为我看待问题的方式有误,如果有人指出如何解析这样的问题,我将不胜感激。


module Main where

import Control.Applicative hiding (many, optional, (<|>))
import Text.ParserCombinators.Parsec
import Numeric (readSigned, readFloat)

commands = command `sepBy` spaces

command = do
  l <- letter
  ns <- number `sepBy` spaces
  return (l, ns)

main :: IO ()
main = print $ show $ parse commands "error" "a 1 2 3 b 4 5 6 d 7 e f"

number :: CharParser () Double
number = do s <- getInput
            case readSigned readFloat s of
              [(n, s')] -> n <$ setInput s'
              _         -> empty

尝试在每个非 space 令牌之后消耗 spaces。例如

commands = many (command <* spaces)

command = do
  l <- letter
  spaces
  ns <- many (number <* spaces)
  return (l, ns)

command = (,) <$> (letter <* spaces) <*> many (number <* spaces)

主要思想是:在你解析某些东西之后,下一个字符应该是非space开始下一个要解析的项目。

我会按照@chi 的建议编写解析器。

sepBy 的处理是,如果分隔符匹配,则 sepBy 期望解析另一个项目。