我试图从Yorgey教授S Expressions为2013 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
定义有什么问题?请不要给我整个答案,而是给我一个暗示 - 为了我自己的学习。
答案 0 :(得分:2)
我对zeroOrMore spaces
非常怀疑,因为spaces
通常是本身解析零个或多个空格的解析器。这意味着如果该点没有任何空格,它可以解析空字符串。特别是,spaces
解析器始终成功。
但是,当您将zeroOrMore
应用于始终成功的解析器时,组合解析器将永远不会停止 - 因为zeroOrMore
仅在解析器参数失败后才会再次停止尝试。
另外,Applicative
只使用一个子分析符的(\_ _ x _ _ _ -> x) <$> ... <*> ... <*> ......
表达式通常可以用*>
和<*
组合器更简洁地编写:
... *> ... *> x_parser_here <* ... <* ...