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

使用FParsec解析嵌套布尔表达式时遇前向引用重复定义错误

解决FParsec互递归解析器的重复定义错误

你尝试用FParsec解析嵌套布尔表达式时遇到了Error FS0037: Duplicate definition of value 'predicateListRef'错误,问题出在重复定义了同一个变量,以下是具体分析和修正方案:

错误原因

createParserForwardedToRef()已经返回了元组(predicateList, predicateListRef),其中predicateListRef是一个可修改的引用,用于后续绑定实际的解析逻辑。但你最后一行又用let predicateListRef重新定义了同名变量,违反了F#的变量定义规则,导致重复定义错误。

正确的做法是给引用赋值,而非重新定义变量,F#中对引用赋值需要使用:=操作符。

修正后的完整代码

open FParsec

type Predicate =
    | True
    | False
    | And of Predicate list
    | Or of Predicate list

let leftParen: Parser<_, unit> = skipChar '('
let rightParen: Parser<_, unit> = skipChar ')'
let comma: Parser<_, unit> = skipChar ','
let keywordTrue: Parser<_,unit> = skipString "true" >>% Predicate.True  
let keywordFalse: Parser<_,unit> = skipString "false" >>% Predicate.False  
let keywordAnd: Parser<_,unit> = skipString "and"
let keywordOr: Parser<_,unit> = skipString "or"

////// 处理递归解析器
let predicateList, predicateListRef = createParserForwardedToRef()

let primePredicate = choice [
    keywordTrue
    keywordFalse
]

let conjunction = (keywordAnd >>. leftParen >>. predicateList) .>> rightParen |>> Predicate.And
let disjunction = (keywordOr >>. leftParen >>. predicateList) .>> rightParen |>> Predicate.Or

let compoundPredicate = choice [
    conjunction
    disjunction
]

let predicate = choice [
    primePredicate
    compoundPredicate
]

// 给引用赋值,而非重新定义变量
predicateListRef := sepBy1 predicate comma

额外说明

  • createParserForwardedToRef的作用是创建一个“占位”解析器和对应引用,用来处理互递归的语法结构(比如这里predicate依赖predicateList,而predicateList又依赖predicate)
  • 最后通过predicateListRef := ...把实际的列表解析逻辑绑定到之前的占位引用上,递归关系就能正确建立

内容的提问来源于stack exchange,提问作者bookofproofs

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 18:31:10