You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.12 04:52:48