7

在正常情况下,F# 函数可以通过调用new DelegateType并作为参数传入函数来转换为委托。但是当委托包含byref参数时,这是不可能的。例如代码:

type ActionByRef<'a> = delegate of 'a byref -> unit

let f (x:double byref) = 
    x <- 6.0

let x = ref 42.0
let d = new ActionByRef<_>(f)

无法编译,出现以下错误:

此函数值用于构造其签名包含 byref 参数的委托类型。您必须使用带有 1 个参数的显式 lambda 表达式。

出现错误后,修改代码以使用

let d = new ActionByRef<_>(fun x -> f(&x))

作品。但我的问题是:为什么这是必要的?为什么 F# 不允许从命名函数转换到此委托,但从 lambda 转换没问题?

我在研究另一个问题时遇到了这种行为。我意识到byref这只是为了与其他 .Net 语言兼容。

4

1 回答 1

11

我认为问题在于它byref<'T>不是 F# 中的实际类型 - 它看起来像一个类型(为了使语言更简单),但它被编译为标有out标志的参数。这意味着byref<'T>只能在编译器实际可以使用out标志的地方使用。

函数值的问题是您可以通过部分应用来构造函数:

let foo (n:int) (b:byref<int>) = 
  b <- n

当您foo作为参数传递给委托构造函数时,它是部分应用程序(没有参数)的特定情况,但部分应用程序实际上需要构造一个新方法,然后将其提供给委托:

type IntRefAction = delegate of byref<int> -> unit  

let ac = IntRefAction(foo 5)

编译器可以很聪明,使用byref参数(或out标志)生成新方法,然后通过引用实际函数将其传递,但​​通常,当您不使用fun ... -> ...语法时,还会有其他编译器生成的方法。处理这会增加复杂性,我认为这是一个相对罕见的情况,所以 F# 编译器不会这样做,并要求你更明确......

于 2012-01-31T11:35:41.267 回答