functional-programming - F#如何定义“递归”变量
问题描述
我正在使用 FParsec 库为伪语言编写一个解析器,我有一个语句解析器,它是在所有可能的语句之间选择一个块解析器,它解析一系列语句,直到一个“结束”关键字,现在我想编写一个“循环”结构,问题是,循环本身是一个语句,并且包含一个块,这导致了一个递归形式的定义,F# 不喜欢我之前在 C# 中编写了一个解析器,并且通过这很容易,因为每个解析器都是一个函数,并且它们可以相互调用,而不管它们是在之前还是之后定义的
所以我想知道如何在 F# 中解决这个问题
这是提到的解析器:
// parses a list of statements, separated by 1 or more newlines, (pre|post)fixed by any amount of whitespace, and finishes parsing upon reaching an "end" keyword
let block endtag = many1Till (statement .>> nl) (skipString endtag) // at this moment, statement is undefined
// parses a loop structure; the keyword loop, followed by an identifier for the iteration variable, followed by an expression which evaluates to the amount iterations which should be executed, followed by a block closed with "endloop"
let loop = skipString "loop" >>. ws1 >>. id .>> ws1 .>>. expr .>> nl .>>. block "endloop" |>> fun ((i, n), s) -> Loop (i, n, s)
// parses any statement, pre or post fixed by any amount of whitespace
let statement = spaces >>. choice [writeline; write; comment; definition; loop; sleep; assignment] .>> spaces
解决方案
FParsec 通过createParserForwardedToRef
. 本教程中描述的 JSON 解析器展示了如何使用它。以下是相关信息的摘录:
JSON 列表和对象的语法规则是递归的,因为任何列表或对象都可以包含任何类型的 JSON 值。因此,为了为列表和对象语法规则编写解析器,我们需要一种方法来为任何类型的 JSON 值引用解析器,即使我们还没有构建这个解析器。就像在计算中经常发生的那样,我们可以通过引入额外的间接来解决这个问题:
let jvalue, jvalueRef = createParserForwardedToRef<Json, unit>()
正如您可能从名称中猜到的那样,
createParserForwardedToRef
创建一个解析器 (jvalue
),它将所有调用转发到引用单元 (jvalueRef
) 中的解析器。最初,参考单元拥有一个虚拟解析器,但由于参考单元是可变的,一旦我们完成构造,我们可以稍后用实际值解析器替换虚拟解析器。
推荐阅读
- c++ - dlsym() + RTLD_NEXT 在 Ubuntu 20.04 上无法按预期工作
- google-bigquery - 如何消除错误结果
- reactjs - 在axios reactjs中动态改变内容类型
- php - 如何在php中规范文件夹中照片的命名?
- c# - 我想在派生类中覆盖 ToolStripButton 控件的一些属性
- python - 如何在 Python Pandas 的 DataFrame 中基于 NLP 选择值?
- jenkins - Jenkins 脚本化流水线:Groovy if 语句
- plot - spss:导出cox回归生存函数图点
- r - 为什么我不能在 R 中将两个文件与 left_join 合并?
- c++ - realloc 在 C++ 中关于额外空间的行为如何?