类中 let 绑定的显式类型参数

9

当我尝试创建一些类时,如下所示:

type MyType () =
    let func<'T> () = ()

编译器显示错误消息:

显式类型参数只能用于模块或成员绑定

MSDN上说:

在模块级别、类型中或计算表达式中的let绑定可以具有显式类型参数。在表达式中的let绑定,例如在函数定义中,不能具有类型参数。

为什么文档和编译器说的不一样?

2
那个 let 可能需要改成 member - leppie
1
规范也禁止它(通过省略和更具体地在语法上)。 - John Palmer
2个回答

5

这似乎是类内部let绑定的一种语法限制。但是,您仍然可以定义一个通用的本地函数,只需在类型注释中指定类型参数:

type MyType () =
   let func (x : 'T) : 'T = x

我认为规范没有明确地语法上禁止这样做,因为规范指出类定义具有以下结构:

类型 类名 模式可选 as-defnopt =
      继承类声明可选
      类函数或值定义可选
      类型定义元素

class-or-value-defn的定义如下:

类函数或值定义 := 属性可选 static可选 let rec可选 函数或值定义集合

其中function-or-value-defns可以是具有显式类型参数的函数定义:

函数定义 :=
inline可选 access可选 标识符或运算符类型参数定义可选 参数模式 返回类型可选 = 表达式


那么MSDN错了,说我们可以在类型内部有显式类型参数吗? - Dmitrii Lobanov
除非你不能:https://dev59.com/TVwY5IYBdhLWcg3wK1P- 所以当编译器决定使类似于您的函数非泛型化(请参见链接的问题)时,我无法添加显式类型参数,必须将我的let绑定转换为成员(具体区别是什么?)。我发誓,我已经使用F#多年了,但有时它的语法感觉就像一场灾难。 - enzi

4

补充Tomas的回答,如果你需要一个类型参数但不会有该类型的值,则可以使用带有幽灵类型参数的类型。例如:

open System

type Foo() =
    member x.PrintType<'T> () = printfn "%s" typeof<'T>.Name

type TypeParameter<'a> = TP

let foo = Foo ()

let callFoo (typeParameter : TypeParameter<'a>) =
    foo.PrintType<'a> ()

callFoo (TP : TypeParameter<string>)
callFoo (TP : TypeParameter<DateTime>)

哇,有了这个技巧,我们可以在一个缺乏typedef-in-a-type(我来自C ++)的编程语言中实现类型级函数。 - nodakai

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接