2012-01-31 39 views
6

在正常情況下,可以通過調用new DelegateType並將該函數作爲參數傳遞,將F#函數轉換爲代表。但是當代表包含byref參數時,這是不可能的。例如代碼:爲什麼不能將帶有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) 

將無法​​編譯,給了以下錯誤:

This function value is being used to construct a delegate type whose signature includes a byref argument. You must use an explicit lambda expression taking 1 arguments.

繼錯誤,修改代碼以使用

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

作品。但我的問題是:爲什麼這是必要的?爲什麼F#不允許從命名函數到這個代理的轉換,但是lambda轉換很好?

我在研究another question時遇到了這種行爲。我知道byref僅用於與其他.Net語言兼容。

回答

10

我認爲這個問題是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#編譯器不會這樣做,並要求您更加明確......

+0

有趣的是,我沒有想到這一點。一個挑逗,我認爲'byref'更像'ref',而不是'out'。 – svick 2012-01-31 11:45:05

+0

@svick - 你是對的 - 實際上,在IL級別,標誌是'ref',並且C#'out'根本不存在... – 2012-01-31 13:00:41

+0

Right,C#的'out'實際上是'ref'加上'System.Runtime.InteropServices.Out'屬性。 – ildjarn 2012-01-31 20:23:57

相關問題