gpt4 book ai didi

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

转载 作者:行者123 更新时间:2023-12-03 01:32:52 29 4
gpt4 key购买 nike

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

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

Ast.hs

data Expr = Const Integer
| BinOp Op Expr Expr
| Neg Expr
| If Expr Expr Expr
| Var String
| Lambda [String] Stmt
deriving (Show, Eq)

data Op = Multiply
| Divide
| Add
| Subtract
deriving (Show, Eq)

data Stmt = Decl String Expr
| Seq [Stmt]
| Print Expr
| Return Expr
deriving (Show, Eq)

解析器.hs

module Parser where

import Ast

import Control.Monad
import Data.Void
import Control.Monad.Combinators.Expr
import Text.Megaparsec
import Text.Megaparsec.Char
import qualified Text.Megaparsec.Char.Lexer as L

type Parser = Parsec Void String

sc :: Parser ()
sc = L.space space1 lineCmnt blockCmnt
where lineCmnt = L.skipLineComment "--"
blockCmnt = L.skipBlockComment "{-" "-}"

lexeme :: Parser a -> Parser a
lexeme = L.lexeme sc

symbol :: String -> Parser String
symbol = L.symbol sc

parens :: Parser a -> Parser a
parens = between (symbol "(") (symbol ")")


integer :: Parser Integer
integer = lexeme L.decimal

rword :: String -> Parser ()
rword w = (lexeme . try) (string w *> notFollowedBy alphaNumChar)

rws :: [String] -- list of reserved words
rws = ["if", "then", "else", "let", "print", "lambda", "return"]

identifier :: Parser String
identifier = (lexeme . try) (p >>= check)
where
p = (:) <$> letterChar <*> many alphaNumChar
check x = if x `elem` rws
then fail $ "keyword " ++ show x ++ " cannot be an identifier"
else return x

ifExpr :: Parser Expr
ifExpr = do rword "if"
cond <- expr
rword "then"
thn <- expr
rword "else"
els <- expr
return $ If cond thn els

lambdaExpr :: Parser Expr
lambdaExpr = do rword "lambda"
args <- parens $ sepBy identifier (char ',')
s <- stmt
return $ Lambda args s

expr :: Parser Expr
expr = makeExprParser term operators

term :: Parser Expr
term = parens expr
<|> lambdaExpr
<|> Const <$> integer
<|> Var <$> identifier
<|> ifExpr

operators :: [[Operator Parser Expr]]
operators =
[ [Prefix (Neg <$ symbol "-") ]
, [ InfixL (BinOp Multiply <$ symbol "*")
, InfixL (BinOp Divide <$ symbol "/") ]
, [ InfixL (BinOp Add <$ symbol "+")
, InfixL (BinOp Subtract <$ symbol "-") ]
]

declStmt :: Parser Stmt
declStmt = do rword "let"
name <- identifier
void $ symbol "="
e <- expr
return $ Decl name e

printStmt :: Parser Stmt
printStmt = do rword "print"
e <- expr
return $ Print e

returnStmt :: Parser Stmt
returnStmt = do rword "return"
e <- expr
return $ Return e

stmt :: Parser Stmt
stmt = f <$> sepBy1 stmt' (symbol ";")
where
-- if there's only one stmt return it without using ‘Seq’
f l = if length l == 1 then head l else Seq l

stmt' :: Parser Stmt
stmt' = declStmt
<|> printStmt
<|> returnStmt

runParser :: Parser a -> String -> Either (ParseError (Token String) Void) a
runParser p input = Text.Megaparsec.runParser p "" input

最佳答案

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

关于Haskell Megaparsec - 保留字解析为标识符,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/53239098/

29 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com