8

在 Visual Studio 2012 中使用 F#,此代码编译:

let ``foo.bar`` = 5

但是这段代码没有:

type ``foo.bar`` = class end

Invalid namespace, module, type or union case name

根据F# 语言规范的第 3.4 节:

Any sequence of characters that is enclosed in double-backtick marks (````),
excluding newlines, tabs, and double-backtick pairs themselves, is treated
as an identifier.

token ident =
    | ident-text
    | `` [^ '\n' '\r' '\t']+ | [^ '\n' '\r' '\t'] ``

第 5 节将类型定义为:

type := 
    ( type )
    type -> type       -- function type
    type * ... * type  -- tuple type
    typar              -- variable type
    long-ident         -- named type, such as int
    long-ident<types> -- named type, such as list<int>
    long-ident< >      -- named type, such as IEnumerable< >
    type long-ident    -- named type, such as int list
    type[ , ... , ]    -- array type
    type lazy          -- lazy type
    type typar-defns   -- type with constraints
    typar :> type      -- variable type with subtype constraint
    #type              -- anonymous type with subtype constraint

...并且第 4.2 节将 long-ident 定义为:

long-ident :=  ident '.' ... '.' ident

据我从规范中可以看出,类型是用长标识命名的,长标识可以是标识。由于 idents 支持双反引号引用的标点符号,因此类型似乎也应该如此。

那么我是否误读了规范?或者这是一个编译器错误?

4

1 回答 1

13

看起来规范与实际实现显然不同步,因此在一侧或另一侧存在错误。

当您在双反引号中使用标识符时,编译器将其视为名称并简单地生成具有您在反引号中指定的名称的类型(或成员)。它不进行任何名称修改以确保标识符是有效的类型/成员名称。

这意味着您不能使用与编译代码中的某些标准含义相冲突的标识符并不奇怪。在您的示例中,它是点,但这里有一些其他示例:

type ``Foo.Bar``() =  // Dot is not allowed because it represents namespace
    member x.Bar = 0

type ``Foo`1``() =    // Single backtick is used to compile generic types
    member x.Bar = 0

type ``Foo+Bar``() =  // + is used in the name of a nested type
    member x.Bar = 0

上面的示例不允许作为类型名称(因为它们与某些标准含义冲突),但您可以在 let-bindings 中使用它们,因为变量名称没有这样的限制:

let ``foo`1`` = 0
let ``foo.bar`` = 2
let ``foo+bar`` = 1

这绝对是应该在文档和规范中解释的东西,但我希望这有助于澄清正在发生的事情。

于 2012-10-20T14:23:58.757 回答