让绑定支持双重反引号中的标点符号,但类型不支持?

时间:2012-10-20 05:12:50

标签: f# visual-studio-2012

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

let ``foo.bar`` = 5

但是这段代码没有:

type ``foo.bar`` = class end

Invalid namespace, module, type or union case name

根据F# language specification的第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

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

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

1 个答案:

答案 0 :(得分:12)

看起来规范与实际实现不一致,因此一方或另一方存在错误。

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

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

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

这绝对应该在文档&amp;规范,但我希望这有助于澄清正在发生的事情。