为什么显式泛型函数值与类似的非泛型不同?

Gen*_*ski 5 generics f#

我们来看一个简单的函数值f1:

let f1 = printfn "*bind f1*"; fun () -> printfn "f1()"
Run Code Online (Sandbox Code Playgroud)

f1 在FSI中绑定为

*bind f1*
val f1 : (unit -> unit)
Run Code Online (Sandbox Code Playgroud)

并且,被调用,表现如预期

> () |> f1 |> f1;;
f1()
f1()
val it : unit = ()
Run Code Online (Sandbox Code Playgroud)

现在让我们采用类似的函数值,但明确地通用f2<'a>:

let f2<'a> = printfn "*bind f2*"; fun () -> printfn "f2()"
Run Code Online (Sandbox Code Playgroud)

f2 在FSI中绑定为

val f2<'a> : (unit -> unit)
Run Code Online (Sandbox Code Playgroud)

没有任何*bind f2*输出,但随后被调用,在每次f2调用时输出:

> () |> f2 |> f2;;
*bind f2*
f2()
*bind f2*
f2()
val it : unit = ()
Run Code Online (Sandbox Code Playgroud)

我的问题是:这种观察到的差异可能是什么原因?

Tom*_*cek 4

F#通常不允许创建泛型值,因为这会带来“值限制”困难(即,您无法创建泛型语法值,即使它是返回函数的代码)。所以,你f2不应该被允许,但是......

该规则有一个例外 - 拥有像 and 这样的泛型值通常很有用,List.empty因此如果您使用显式泛型类型参数声明一个值,它实际上会被编译成返回结果的函数。

这正是您的示例中发生的情况:

let f2<'a> = printfn "*bind f2*"; fun () -> printfn "f2()"
Run Code Online (Sandbox Code Playgroud)

这里,f2是一个泛型值(即使它在任何地方都没有真正使用类型参数),但它有一个显式的泛型类型参数,因此它实际上被编译成一个方法,每次访问时都会调用该方法f2并返回结果(功能unit -> unit

我在规范中找不到对此的任何明确解释,但有一篇很好的 MSDN 文章(参见“案例 4”)以及前 F# 团队成员的博客