【问题标题】:FParsec Not Recognizing a Type’s ConstructorFParsec 无法识别类型的构造函数
【发布时间】:2020-12-26 20:02:15
【问题描述】:

以下顶级 XML 解析器定义返回错误 The value or constructor ‘TOP_LEVEL_RECORD’ is not defined. ...

let xTop_Level, xTop_Level_Ref = createParserForwardedToRef<TOP_LEVEL_RECORD, unit>()

do xTop_Level_Ref := 
    pipe4 
        (opt xDeclaration) 
        (opt (many xComment_or_CData))
        xElement
        (opt (many xComment_or_CData))
        (fun decl before_root root after_root
            -> {Declaration = decl
                Before_Root = before_root
                Root = root
                After_Root = after_root}) |>> TOP_LEVEL_RECORD
// This returns the error -------------------→^^^^^^^^^^^^^^^^

TOP_LEVEL_RECORD 被定义为……

type TOP_LEVEL_RECORD = {Declaration : XDECLARATION option
                         Before_Root : COMMENTS_OR_CDATA list option
                         Root : XELEMENT
                         After_Root : COMMENTS_OR_CDATA list option
                         }

解析器xDeclarationxCommentor_CdataxElement都被正确定义并返回TOP_LEVEL_RECORD中对应的类型。

let xTop_Level, xTop_Level_Ref = createParserForwardedToRef&lt;TOP_LEVEL_RECORD, unit&gt;() 是 Fparsec 用于递归解析器调用的语法,记录在此:http://www.quanttec.com/fparsec/tutorial.html#parsing-json.createParserForwardedToRef-example

如果我定义类型 type TOP_LEVEL = TOP_LEVEL_TYPE of TOP_LEVEL_RECORD 并将 TOP_LEVEL_RECORD 替换为 TOP_LEVELTOP_LEVEL_TYPE 如下......

let xTop_Level, xTop_Level_Ref = createParserForwardedToRef<TOP_LEVEL, unit>()
// Replaced this text ------------------------------------->^^^^^^^^^

do xTop_Level_Ref := 
    pipe4 
        (opt xDeclaration) 
        (opt (many xComment_or_CData))
        xElement
        (opt (many xComment_or_CData))
        (fun decl before_root root after_root
            -> {Declaration = decl
                Before_Root = before_root
                Root = root
                After_Root = after_root}) |>> TOP_LEVEL_TYPE
// Replaced this text ----------------------->^^^^^^^^^^^^^^

...代码编译没有任何错误或警告。

为什么TOP_LEVEL_TYPE在这里有构造函数而不是TOP_LEVEL_RECORD

您能否指出 F# 或 FParsec 文档的相关部分?

【问题讨论】:

    标签: f# fparsec


    【解决方案1】:

    TOP_LEVEL_RECORD(记录类型)和TOP_LEVEL(联合类型)是类型名称,不能用作构造函数。

    要构造TOP_LEVEL_RECORD,请使用代码中的语法

    { Declaration = decl
      Before_Root = before_root
      Root = root
      After_Root = after_root }
    

    要构造联合类型的实例,您可以使用其中一个案例名称作为构造函数; TOP_LEVEL_TYPE 在你的情况下,因为只有一个联合案例。

    请注意,在您的类型定义中

    type TOP_LEVEL = TOP_LEVEL_TYPE of TOP_LEVEL_RECORD
    

    TOP_LEVEL 是一个类型,但TOP_LEVEL_TYPE(尽管它的名字)不是一个类型,而是TOP_LEVEL 类型的构造函数。

    所以记录类型没有命名构造函数,但联合类型有。

    对于您的代码,您可以跳过 |&gt;&gt; TOP_LEVEL_RECORD 部分。

    您可以在F# language spec,第 8.4 和 8.5 节中阅读有关记录类型和联合类型的信息。

    【讨论】:

    • 感谢您提供指向该文档的指针。我以前只看过 MSFT 文档。但是只有 8.5 提到了“联合案例名称”,并且没有任何地方将联合案例名称用作构造函数引用。对可能是构造函数标签的联合案例名称的最接近引用位于第 137 页,“一个 CLI 静态方法 U.NewCfor 每个非空联合案例 C。此方法为该案例构造一个对象。”但这很模糊。是否有文档直接说联合案例名称是构造函数?另外我的代码type TOP_LEVEL = TOP_LEVEL_TYPE of TOP_LEVEL_RECORD 不是联合案例,它是什么?
    • 你的类型TOP_LEVEL真的联合类型,但只有一种情况。您可以找到有关作为构造函数的案例名称的信息here
    • 谢谢。构造函数和类型名称以及相关的语法糖之间的这种区别似乎没有必要。 F# 不能从上下文中得知类型名称被用作构造函数吗?是否存在可以自定义记录构造函数的情况,也许是为了设置默认值,但仍然允许使用 |> 运算符?
    猜你喜欢
    • 2017-03-16
    • 1970-01-01
    • 1970-01-01
    • 2019-11-12
    • 1970-01-01
    • 2019-12-29
    • 1970-01-01
    • 2021-07-23
    • 2016-02-02
    相关资源
    最近更新 更多