Haskell Parsec在语法中考虑了多个表达式的隐含

时间:2013-02-28 10:53:47

标签: haskell parsec

我一直在尝试使用以下tutorial

中的详细信息创建解析器

大部分代码都直接从教程中复制,只更改了几个名称。

import qualified Text.ParserCombinators.Parsec.Token as P 

reserved   = P.reserved   lexer  
integer    = P.integer    lexer
whiteSpace = P.whiteSpace lexer
identifier = P.identifier lexer

data Express = Seq [Express]
          | ID String
          | Num Integer
          | BoolConst Bool
          deriving (Show)

whileParser :: Parser Express
whileParser = whiteSpace >> expr7

expr7 = seqOfStmt 
    <|> expr8        

seqOfStmt =         
    do list <- (sepBy1 expr8 whiteSpace)
    return $ if length list == 1 then head list else Seq list

expr8 :: Parser Express
expr8 = name 
    <|> number
    <|> bTerm

name :: Parser Express
name = fmap ID identifier

number :: Parser Express
number = fmap Num integer

bTerm :: Parser Express
bTerm = (reserved "True"  >> return (BoolConst True ))
    <|> (reserved "False" >> return (BoolConst False))

我知道这段代码可能很可笑,但我真的想更多地了解一下我出错的地方。我也认为这应该提供足够的信息,但如果不让我知道。

Error:
parse error on input `return'  

我认为错误与不同的返回类型有关,这很奇怪,因为我试图在帖子开头使用教程作为我尝试的所有内容的基础。

提前致谢,

肖恩

1 个答案:

答案 0 :(得分:3)

如果您对布局规则不满意,也可以使用不同的语法:

seqOfStmt =         
   do { list 
 <- (sepBy1 expr8 whiteSpace);
       return $ if length 
            list == 1 
        then head list else Seq list;}

没有大括号和分号的布局被认为是优越的,但有两个原因:

  1. 你不需要输丑;和大括号
  2. 它强迫你写(大多数)可读代码,不像我上面给出的扭曲的废话。
  3. 规则很简单:

    1. 不要使用制表符,请使用空格。总是。 (你的编辑可以这样做,如果没有,扔掉它,它是crapware。)
    2. 属于一起的东西必须在同一列中对齐。
    3. 例如,您有2个属于 do 块的语句,因此它们必须在同一列中对齐。但是您已将returndo对齐,因此编译器将其视为:

      do { list <- sepBy1 expr8 whiteSpace; };
      return $  ....;
      

      但你想要的是:

      do {
          list <- sepBy1 ....;
          return $ .....;
      }
      

      (注意你可以省略大括号和分号,只要你让缩进完好无损就可以了。