为S表达式编写解析器

时间:2015-01-13 04:57:58

标签: parsing haskell

我试图从Yorgey教授S Expressions2013 homework写一个Parser。

newtype Parser a = Parser { runParser :: String -> Maybe (a, String) }

鉴于以下定义,在作业中提出:

type Ident = String

-- An "atom" is either an integer value or an identifier.
data Atom = N Integer | I Ident
  deriving Show

-- An S-expression is either an atom, or a list of S-expressions.
data SExpr = A Atom
           | Comb [SExpr]
  deriving Show

我为Parser Atom编写了一个解析器,为Parser SExpr编写了A Atom

parseAtom :: Parser Atom
parseAtom = alt n i
   where n = (\_ z -> N z) <$> spaces <*> posInt
         i = (\ _ z -> I z) <$> spaces <*> ident

parseAAtom :: Parser SExpr
parseAAtom = fmap (\x -> A x) parseAtom 

然后,我尝试编写一个解析器来处理Parser SExpr案例的Comb ...

parseComb :: Parser SExpr
parseComb = (\_ _ x _ _ _ -> x) <$> (zeroOrMore spaces) <*> (char '(') <*> 
                                     (alt parseAAtom parseComb) <*> (zeroOrMore spaces) 
                                        <*> (char ')') <*> (zeroOrMore spaces)

假设parseComb是正确的,我可以只为oneOrMore使用Parser [SExpr]

parseCombElements :: Parser [SExpr]
parseCombElements = oneOrMore parseComb

所以,我的两个最后一个函数编译,但运行runParser parseComb "( foo )"永远不会终止。

我的parseComb定义有什么问题?请不要给我整个答案,而是给我一个暗示 - 为了我自己的学习。

1 个答案:

答案 0 :(得分:2)

我对zeroOrMore spaces非常怀疑,因为spaces通常是本身解析零个或多个空格的解析器。这意味着如果该点没有任何空格,它可以解析空字符串。特别是,spaces解析器始终成功

但是,当您将zeroOrMore应用于始终成功的解析器时,组合解析器将永远不会停止 - 因为zeroOrMore仅在解析器参数失败后才会再次停止尝试。

另外,Applicative只使用一个子分析符的(\_ _ x _ _ _ -> x) <$> ... <*> ... <*> ......表达式通常可以用*><*组合器更简洁地编写:

... *> ... *> x_parser_here <* ... <* ...
相关问题