Haskell Megaparsec - 保留字解析为标识符

Phi*_*tel 5 haskell megaparsec

我正在尝试用 lamdba 表达式解析一种简单的语言。但runParser expr "lamdbda(x) (return x)返回Right (Var "lamdba")而不是Right (Lambda ["x"] (Return (Var "x")))

\n\n

我的猜测是,我必须try在某个地方添加一个,但我不知道在哪里。lambdaExpr正确解析 lamdbas。

\n\n

AST.HS

\n\n
data Expr = Const Integer\n          | BinOp Op Expr Expr\n          | Neg Expr\n          | If Expr Expr Expr\n          | Var String\n          | Lambda [String] Stmt\n  deriving (Show, Eq)\n\ndata Op = Multiply\n        | Divide\n        | Add\n        | Subtract\n  deriving (Show, Eq)\n\ndata Stmt = Decl String Expr\n          | Seq [Stmt]\n          | Print Expr\n          | Return Expr\n  deriving (Show, Eq)\n
Run Code Online (Sandbox Code Playgroud)\n\n

解析器.hs

\n\n
module Parser where\n\nimport Ast\n\nimport Control.Monad\nimport Data.Void\nimport Control.Monad.Combinators.Expr\nimport Text.Megaparsec\nimport Text.Megaparsec.Char\nimport qualified Text.Megaparsec.Char.Lexer as L\n\ntype Parser = Parsec Void String\n\nsc :: Parser ()\nsc = L.space space1 lineCmnt blockCmnt\n  where lineCmnt = L.skipLineComment "--"\n        blockCmnt = L.skipBlockComment "{-" "-}"\n\nlexeme :: Parser a -> Parser a\nlexeme = L.lexeme sc\n\nsymbol :: String -> Parser String\nsymbol = L.symbol sc\n\nparens :: Parser a -> Parser a\nparens = between (symbol "(") (symbol ")")\n\n\ninteger :: Parser Integer\ninteger = lexeme L.decimal\n\nrword :: String -> Parser ()\nrword w = (lexeme . try) (string w *> notFollowedBy alphaNumChar)\n\nrws :: [String] -- list of reserved words\nrws = ["if", "then", "else", "let", "print", "lambda", "return"]\n\nidentifier :: Parser String\nidentifier = (lexeme . try) (p >>= check)\n  where\n    p       = (:) <$> letterChar <*> many alphaNumChar\n    check x = if x `elem` rws\n              then fail $ "keyword " ++ show x ++ " cannot be an identifier"\n              else return x\n\nifExpr :: Parser Expr\nifExpr = do rword "if"\n            cond <- expr\n            rword "then"\n            thn <- expr\n            rword "else"\n            els <- expr\n            return $ If cond thn els\n\nlambdaExpr :: Parser Expr\nlambdaExpr = do rword "lambda"\n                args <- parens $ sepBy identifier (char \',\')\n                s <- stmt\n                return $ Lambda args s\n\nexpr :: Parser Expr\nexpr = makeExprParser term operators\n\nterm :: Parser Expr\nterm = parens expr\n  <|> lambdaExpr\n  <|> Const <$> integer\n  <|> Var <$> identifier\n  <|> ifExpr\n\noperators :: [[Operator Parser Expr]]\noperators =\n  [ [Prefix (Neg <$ symbol "-") ]\n  , [ InfixL (BinOp Multiply <$ symbol "*")\n    , InfixL (BinOp Divide   <$ symbol "/") ]\n  , [ InfixL (BinOp Add      <$ symbol "+")\n    , InfixL (BinOp Subtract <$ symbol "-") ]\n  ]\n\ndeclStmt :: Parser Stmt\ndeclStmt = do rword "let"\n              name <- identifier\n              void $ symbol "="\n              e <- expr\n              return $ Decl name e\n\nprintStmt :: Parser Stmt\nprintStmt = do rword "print"\n               e <- expr\n               return $ Print e\n\nreturnStmt :: Parser Stmt\nreturnStmt = do rword "return"\n                e <- expr\n                return $ Return e\n\nstmt :: Parser Stmt\nstmt = f <$> sepBy1 stmt\' (symbol ";")\n  where\n    -- if there\'s only one stmt return it without using \xe2\x80\x98Seq\xe2\x80\x99\n    f l = if length l == 1 then head l else Seq l\n\nstmt\' :: Parser Stmt\nstmt\' = declStmt\n        <|> printStmt\n        <|> returnStmt\n\nrunParser :: Parser a -> String -> Either (ParseError (Token String) Void) a\nrunParser p input = Text.Megaparsec.runParser p "" input\n
Run Code Online (Sandbox Code Playgroud)\n

Phi*_*tel 1

我拼错了“lambda”,结束了这个问题。