2012-01-31 19 views
6

通常、F#関数はnew DelegateTypeを呼び出し、引数として関数を渡すことによって代理人に変換できます。しかし、代理人にbyrefパラメータが含まれている場合、これは直接行うことはできません。たとえばコード:byrefのある関数を代理人に直接変換できないのはなぜですか?

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

作品を使用するようにコードを修正し、エラー後

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.

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) 

は、次のエラーを与えて、コンパイルされません。しかし、私の質問は、なぜこれが必要なのでしょうか?なぜ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フラグ)と新しいメソッドを生成し、実際の関数を参照することによってそれを通過するが、一般的に、他のcompiler-が存在することになる可能性を使用しないときに生成されたメソッド構文。これを処理すると複雑さが増し、それは比較的まれなケースだと思うので、F#コンパイラはそれを実行せず、もっと明示するように尋ねます...

+0

興味深いことに、私はそれを考えませんでした。 1つのニックピック、私は 'byref'は' ref'と似ていて、 'out'ではないと思う。 – svick

+0

@svick - あなたは正しい - 実際、ILレベルでは、フラグは 'ref'であり、C#' out'は全く存在しません... –

+0

右、C#の 'out'は実際に' ref'と'System.Runtime.InteropServices.Out'属性です。 – ildjarn

関連する問題