我怎样才能在F#中表达一个可选择自我修复的类型(无限)

时间:2011-06-21 12:28:07

标签: recursion f# types graphviz fparsec

作为一项学习练习,我试图使用功能解析器库fparsec(The DOT language)来为graphviz点语言(FParsec)提供解析器。该语言描述了图表。

查看语言定义我不得不写下以下定义:

let rec pstmt_list = opt(pstmt .>> opt(pchar ';') >>. opt pstmt_list)

pstmtpchar ';'是解析器,.>>>>.将左解析器的出现与右解析器的出现相结合,opt解析器将其参数解析器的可选出现作为选项值。然而,这个定义不起作用抱怨“......结果类型将是无限的...”。

通过查看上面链接的DOT语言,可能最容易理解这个例子。

我知道以下看似相关的问题:

但是我的F#知识可能还不足以翻译它们,如果它们在这里适用的话。

2 个答案:

答案 0 :(得分:4)

FParsec为解析序列提供了特殊的组合子。通常你应该更喜欢这些组合器用递归函数重新实现它们。您可以在此处找到用于解析序列的可用组合子的概述:http://www.quanttec.com/fparsec/reference/parser-overview.html#parsing-sequences

在此示例中,pstmt_list是一系列语句,分隔并可选地以分号结束,因此您可以轻松地将解析器定义为

let pstmt_list = sepEndBy pstmt (pstring ";")

答案 1 :(得分:2)

问题是你的pstmt_list解析器产生了某些类型的值,但是当你在定义中使用它时,你用另外的option类型包装这个类型的值(使用{{ 1}}组合者)。

F#编译器认为解析器返回的值的类型,例如opt应与包装类型'a相同(当然,这是不可能的)。

无论如何,我认为这不是你需要做的事情 - option 'a组合器创建一个返回第二个参数结果的解析器,这意味着你将忽略所有结果到目前为止解析了.>>

我想你可能需要这样的东西:

pstmt

额外使用let rec pstmt_list : Parser<int list, unit> = parse.Delay(fun () -> opt(pstmt .>> pchar ';') .>>. opt pstmt_list |>> (function Some(prev), Some(rest) -> prev::rest | Some(prev), _ -> [prev] | _, Some(rest) -> rest | _ -> [] )) 是为了避免声明一个直接引用自身的值。