F#如何定义“递归”变量

时间:2021-04-16 12:55:47

标签: functional-programming f# fparsec

我正在使用 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

1 个答案:

答案 0 :(得分:2)

FParsec 通过 createParserForwardedToRef 支持递归解析器。 JSON parser described in the tutorial 显示了如何使用它。以下是相关信息的摘录:

<块引用>

JSON 列表和对象的语法规则是递归的,因为任何列表或对象都可以包含任何类型的 JSON 值。因此,为了为列表和对象语法规则编写解析器,我们需要一种方法来为任何类型的 JSON 值引用解析器,即使我们还没有构造这个解析器。就像在计算中经常发生的那样,我们可以通过引入额外的间接来解决这个问题:

<块引用>

let jvalue, jvalueRef = createParserForwardedToRef<Json, unit>()

<块引用>

从名称中您可能已经猜到,createParserForwardedToRef 创建了一个解析器 (jvalue),它将所有调用转发到引用单元格 (jvalueRef) 中的解析器。最初,参考单元格持有一个虚拟解析器,但由于参考单元格是可变的,我们可以在构建完成后将虚拟解析器替换为实际值解析器。

相关问题