使用makeExprParser遇歧义:含>运算符的表达式解析失败
解决方案
你的问题核心是两个点:一是parseInteger强制要求数字后必须跟空白,导致无空白的1223>234无法被解析;二是Megaparsec需要明确表达式的边界,避免把外层的>误判为运算符。以下是可直接运行的修复代码,同时保留makeExprParser的使用:
-- uses megaparsec, text, and parser-combinators {-# LANGUAGE OverloadedStrings #-} module Main where import Control.Monad.Combinators.Expr import Data.Text import Data.Void import System.Environment import Text.Megaparsec import Text.Megaparsec.Char import qualified Text.Megaparsec.Char.Lexer as L type BinaryOperator = Text type Name = Text data Expr = IntExpr Integer | BinaryExpression BinaryOperator Expr Expr deriving (Eq, Show) type Parser = Parsec Void Text lexeme :: Parser a -> Parser a lexeme = L.lexeme sc symbol :: Text -> Parser Text symbol = L.symbol sc sc :: Parser () sc = L.space space1 (L.skipLineComment "//") (L.skipBlockCommentNested "/*" "*/") -- 修复:用lexeme包裹L.decimal,自动处理数字后的空白(包括无空白的情况) parseInteger :: Parser Expr parseInteger = lexeme $ IntExpr <$> L.decimal parseExpr :: Parser Expr parseExpr = makeExprParser parseInteger [[InfixL (BinaryExpression ">" <$ symbol ">")]] parseBracketList :: Parser [Expr] parseBracketList = do _ <- symbol "<" -- 关键:用try确保表达式解析失败时回溯,避免外层>被误吞 exprs <- sepBy (try parseExpr) (symbol ",") _ <- symbol ">" return exprs main :: IO () main = do text : _ <- getArgs let res = runParser parseBracketList "stdin" (pack text) case res of Right suc -> print suc Left err -> putStrLn $ errorBundlePretty err
关键修改说明
- 修复
parseInteger:原代码中手动调用sc强制要求数字后必须有空白,改用lexeme $ L.decimal后,lexeme会自动处理数字后的空白(包括无空白的场景),让1223>234中的1223能被正确解析。 - 添加
try到sepBy:在sepBy (try parseExpr) (symbol ",")中用try包裹parseExpr,确保当表达式解析失败(比如遇到外层>而非运算符>)时,解析器能回溯并终止表达式解析,转而匹配外层的>。
测试输入<1223>234>会输出[BinaryExpression ">" (IntExpr 1223) (IntExpr 234)],完全符合预期。你不需要手动编写表达式解析器,makeExprParser依然可以正常使用。
内容的提问来源于stack exchange,提问作者user1512263
相关产品推荐
相关产品推荐

