Haskell中有理数与算术表达式二元运算Parser实现问题
问题核心原因
- 分支匹配顺序错误:你的
term定义中把Lit <$> rational放在了乘法匹配分支前面,Parsec的<|>运算符是左优先的,只要前面的分支匹配成功就会直接返回结果,不会向后尝试其他分支。你解析10/1 * x时,10/1作为合法Rational匹配到了Lit分支,解析器直接返回结果,不会检查后面的*和x。 - 不需要修改现有数据结构,也不需要调整运算符表,只要调整分支顺序就能解决问题。
修复方案
仅需调换term中乘法分支和Lit分支的顺序,保留原有所有逻辑不变:
aexp :: Parser AExp aexp = buildExpressionParser table term where term = -- 优先匹配「系数 * 表达式」结构,匹配失败再回退到纯字面量解析 try ((:*:) <$> (rational <* reservedOp "*") <*> aexp) <|> Lit <$> rational <|> Var <$> identifier <|> try (parens aexp) table = [ [ binary "+" (:+:)]]
验证结果
修复后运行测试用例:
Main>regularParse aexp "10/1 * x" Right (10 % 1 :*: Var "x")
符合预期,同时纯字面量、加法、括号表达式的解析逻辑不受影响。
扩展说明
如果后续需要支持更复杂的嵌套乘法场景(比如2/1 * (3/1 * x + 1/1)),现有逻辑已经天然支持,不需要额外修改,因为乘法分支的右操作数直接调用了aexp解析器,可以匹配任意合法的线性表达式。
内容的提问来源于stack exchange,提问作者Shenkok Kotoro
相关产品推荐
相关产品推荐

