F# 如何定义 "recursive" 变量
F# how to define "recursive" variables
我正在使用 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 parser described in the tutorial 显示了如何使用它。以下是相关信息的摘录:
The grammar rules for JSON lists and objects are recursive, because any list or object can contain itself any kind of JSON value. Hence, in order to write parsers for the list and object grammar rules, we need a way to refer to the parser for any kind of JSON value, even though we haven’t yet constructed this parser. Like it is so often in computing, we can solve this problem by introducing an extra indirection:
let jvalue, jvalueRef = createParserForwardedToRef<Json, unit>()
As you might have guessed from the name, createParserForwardedToRef
creates a parser (jvalue
) that forwards all invocations to the parser in a reference cell (jvalueRef
). Initially, the reference cell holds a dummy parser, but since the reference cell is mutable, we can later replace the dummy parser with the actual value parser, once we have finished constructing it.
我正在使用 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 parser described in the tutorial 显示了如何使用它。以下是相关信息的摘录:
The grammar rules for JSON lists and objects are recursive, because any list or object can contain itself any kind of JSON value. Hence, in order to write parsers for the list and object grammar rules, we need a way to refer to the parser for any kind of JSON value, even though we haven’t yet constructed this parser. Like it is so often in computing, we can solve this problem by introducing an extra indirection:
let jvalue, jvalueRef = createParserForwardedToRef<Json, unit>()
As you might have guessed from the name,
createParserForwardedToRef
creates a parser (jvalue
) that forwards all invocations to the parser in a reference cell (jvalueRef
). Initially, the reference cell holds a dummy parser, but since the reference cell is mutable, we can later replace the dummy parser with the actual value parser, once we have finished constructing it.