Haskell Parsec解析问题:相邻运算符[$]无法识别的解决方法
解决Parsec解析器无法识别[$x]这类写法的问题
我一眼就看出问题出在你对$的处理上——你把它当成了保留操作符(放在reservedOpNames里),但实际上$是绑定变量的前缀,需要和后面的标识符紧密结合,而Parsec的reservedOp函数有一个关键特性:它会在匹配操作符后,检查后面的字符不是标识符或操作符字符,这就导致$x这种写法直接报错(因为$后面的x是标识符字符,触发了notFollowedBy检查失败)。
具体修改步骤:
1. 调整保留操作符列表
从reservedOpNames中移除"$",因为它不是独立的操作符:
lang :: LanguageDef st lang = emptyDef{ Token.identStart = letter, Token.identLetter = alphaNum, Token.reservedOpNames = ["&", "[", "]"], -- 去掉了"$" Token.reservedNames = ["tt", "ff"] }
2. 修改绑定变量的解析逻辑
把bvar中的op "$"换成直接解析$字符,避免reservedOp的额外检查:
-- Bound Variable bvar :: Parser Binder bvar = do char '$' -- 直接用char解析$,不用reservedOp v <- identifier return $ BVar v
(可选)优化中缀操作符的解析(避免潜在问题)
虽然你说&的写法没问题,但如果想让&和操作符之间完全无空格也能正常解析,建议把andFormula中的op "&"换成Token.symbol "&"——symbol不会做notFollowedBy检查,更适合作为中缀操作符:
-- Conjunction andFormula :: Parser Formula andFormula = buildExpressionParser [[Infix (Token.symbol "&" >> return And) AssocLeft]] formulaTerm
修改后的完整代码
module LogicParser where import System.IO import Control.Monad import Text.ParserCombinators.Parsec import Text.ParserCombinators.Parsec.Expr import Text.ParserCombinators.Parsec.Language import qualified Text.ParserCombinators.Parsec.Token as Token -- Data Structures data Formula = LVar String | TT | FF | And Formula Formula | Bound Binder Formula deriving Show data Binder = BVar String | FVar String deriving Show -- Language Definition lang :: LanguageDef st lang = emptyDef{ Token.identStart = letter, Token.identLetter = alphaNum, Token.reservedOpNames = ["&", "[", "]"], Token.reservedNames = ["tt", "ff"] } -- Lexer for langauge lexer = Token.makeTokenParser lang -- Trivial Parsers identifier = Token.identifier lexer keyword = Token.reserved lexer op = Token.reservedOp lexer roundBrackets = Token.parens lexer whiteSpace = Token.whiteSpace lexer -- Main Parser, takes care of trailing whitespaces formulaParser :: Parser Formula formulaParser = whiteSpace >> formula -- Parsing Formulas formula :: Parser Formula formula = andFormula <|> formulaTerm -- Term in a Formula formulaTerm :: Parser Formula formulaTerm = roundBrackets formula <|> ttFormula <|> ffFormula <|> lvarFormula <|> boundFormula -- Conjunction andFormula :: Parser Formula andFormula = buildExpressionParser [[Infix (Token.symbol "&" >> return And) AssocLeft]] formulaTerm -- Bound Formula boundFormula :: Parser Formula boundFormula = do op "[" v <- var op "]" f <- formulaTerm return $ Bound v f -- Truth ttFormula :: Parser Formula ttFormula = keyword "tt" >> return TT -- Falsehood ffFormula :: Parser Formula ffFormula = keyword "ff" >> return FF -- Logical Variable lvarFormula :: Parser Formula lvarFormula = do v <- identifier return $ LVar v -- Variable var :: Parser Binder var = try bvar <|> fvar -- Bound Variable bvar :: Parser Binder bvar = do char '$' v <- identifier return $ BVar v -- Free Variable fvar :: Parser Binder fvar = do v <- identifier return $ FVar v -- For testing main :: IO () main = interact (unlines . (map stringParser) . lines) stringParser :: String -> String stringParser s = case ret of Left e -> "Error: " ++ (show e) Right n -> "Interpreted as: " ++ (show n) where ret = parse formulaParser "" s
测试验证
现在你可以正常解析以下所有写法:
[$x](x & true)(无空格的绑定器)[ $x ](x & true)(带空格的绑定器)x & true(无空格的中缀操作符)[x]x(普通绑定器)
内容的提问来源于stack exchange,提问作者Luke Collins
相关产品推荐
相关产品推荐

