使Parsec函数失败而不是期望更多输入

时间:2014-10-13 08:34:24

标签: haskell parsec

我正在使用Parsec来解析一些表达式(有关更多上下文,请参阅this question),我的代码中最相关的部分是:

statement :: Parser Stmt
statement = assignStmt <|> simpleStmt

assignStmt :: Parser Stmt
assignStmt =
    do var  <- identifier
       reservedOp "="
       expr <- expression
       return $ Assign var expr

simpleStmt :: Parser Stmt
simpleStmt =
    do expr <- expression
       return $ Simple expr

行动中:

  

boobla&gt; foo = 100 + ~100
  167个
   boobla&gt; foo
  解析器错误:(第1行,第4列):
  意外的输入结束
  期待字母或数字或“=”

第二个表达式应评估为167,值为foo

我认为当Parsec尝试提取令牌reservedOp "="时,它应该失败,因为字符串中没有这样的令牌,然后是尝试第二个函数simpleStmt并成功使用它。但它的工作方式不同:它期望更多的输入,只是抛出这个异常。

如果字符串(或当前行)中没有更多字符,我应该使用什么来使assignStmt失败。应使用foo = 10解析assignStmt,并使用foo解析simpleStmt

1 个答案:

答案 0 :(得分:8)

您错过了try功能。

默认情况下,<|>运算符将尝试使用左解析器,如果失败而不使用任何字符,它将尝试使用正确的解析器。

但是,如果 - 在您的情况下 - 解析器在消耗了一些字符后失败,并且正确的解析器从未尝试过。请注意,这通常是您想要的行为;如果你有像

这样的东西
parseForLoop <|> parseWhileLoop

然后如果输入类似于“for break”,那么这不是一个有效的for循环,并且没有必要尝试将其解析为while循环,因为这肯定也会失败。

try组合器会更改此行为。具体来说,它使失败的解析器似乎没有消耗任何输入。 (这会造成空间损失;输入可能已被丢弃,但try会使其徘徊。)