逻辑公式解析器Either类型列表解析失败问题求助
逻辑公式解析器Either列表解析问题修复方案
问题复现
解析P(f(x:X)=a:A,b:B)时,预期输出:
- 替换项:
[((f,([(x,X)],A),(a,A))] - 谓词:
(P, [(a,A),(b,B)])
实际输出仅为(P, [Left b:B]),替换项完全丢失。但单独用commaSep parseVSub解析f(x:X)=a:A,b:B能得到正确结果[Right (f(x:X),a:A),Left b:B],说明问题出在pparens与commaSep parseVSub的组合逻辑中。
问题根源分析
- 符号处理不一致:代码中混用
string和symbol处理符号,string不会自动跳过前后空格,可能导致解析过程中因空格匹配失败触发回溯,丢失第一个元素。 - 回溯逻辑冗余:
pparens和parsePredSub中的try包裹范围过大,可能在局部解析失败时触发不必要的全局回溯,导致部分元素被跳过。 - 预期与代码逻辑不匹配:当前代码中,替换项里的
a:A不会被加入谓词参数列表,但你的预期中需要包含该元素,这是逻辑设计的偏差。
修复步骤
1. 统一符号解析逻辑
将所有符号((、)、:、=)替换为symbol函数处理,确保自动跳过前后空格,避免因空格导致的解析失败:
parseVS :: Parser VarSrt parseVS = do {v<-identifier; symbol ":"; s<-identifier; return $ (v,s)} pparens :: Parser a -> Parser (String,a) pparens par = do {p<-identifier; symbol "("; z <- par; symbol ")"; return (p,z)} parseSub :: Parser Sub parseSub = do {(f,a) <- pparens (commaSep parseVS); symbol "="; (x,s) <- parseVS; return $ ((f,(a,s)),(x,s))}
2. 优化解析器顺序与回溯
调整parseVSub的解析顺序,先尝试复杂的parseSub再尝试简单的parseVS,减少不必要的回溯;同时移除pparens中的冗余try(因为identifier+(是独特前缀,不会与其他解析器冲突):
parseVSub :: Parser VSub parseVSub = choice [Right <$> try parseSub, Left <$> parseVS]
3. 修正谓词参数逻辑
如果需要将替换项中的VarSrt(即a:A)加入谓词参数列表,调整parsePredSub的返回逻辑:
parsePredSub :: Parser PredSub parsePredSub = do {(p,bc) <- pparens (commaSep parseVSub); let subs = rights bc -- 将替换项中的变量类型对加入谓词参数 params = lefts bc ++ map snd subs return (subs, (p, params))}
验证效果
修复后解析P(f(x:X)=a:A,b:B),将得到:
- 替换项:
[((f,([(x,X)],A),(a,A))] - 谓词:
(P, [(a,A),(b,B)])
完全符合预期。
内容的提问来源于stack exchange,提问作者CB Wells
相关产品推荐
相关产品推荐

