7

new DelegateType通常の状況では、F#関数は、関数を呼び出して引数として渡すことにより、デリゲートに変換できます。ただし、デリゲートに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つの引数を取る明示的なラムダ式を使用する必要があります。

エラーに続いて、使用するコードを変更します

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

動作します。しかし、私の質問は、なぜこれが必要なのかということです。F#で名前付き関数からこのデリゲートへの変換が許可されないのに、ラムダからの変換は問題ないのはなぜですか?

別の質問を調べているときに、この動作に出くわしました。私byrefは、他の.Net言語との互換性のためだけに意図されていることを理解しています。

4

1 に答える 1

11

問題は、F# の実際の型ではないことだと思います。byref<'T>(言語を単純にするために) 型のように見えますが、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 に答える