デリゲート (F#)
デリゲートとは、オブジェクトとして関数を呼び出すことです。F# では、通常、関数を最優先の値として表すために、関数の値を使用する必要があります。ただし、.NET Framework ではデリゲートが使用されるため、デリゲートを受け取る API と相互運用する場合は、デリゲートを使用する必要があります。また、他の .NET Framework 言語から使用するライブラリを作成するときにも、デリゲートを使用します。
type delegate-typename = delegate of type1 -> type2
解説
前の構文の type1 は、1 つまたは複数の引数の型を表し、type2 は戻り値の型を表しています。type1 で表される引数の型は、自動的にカリー化されます。このため、この型には、対象の関数の引数がカリー化される場合にはタプル形式を使用し、引数が既にタプル形式になっている場合にはかっこで囲んだタプルを使用するようにしてください。自動的なカリー化により、一対のかっこが削除され、対象のメソッドと一致するタプルの引数になります。それぞれの場合に使用する構文については、コード例を参照してください。
デリゲートは、F# 関数値、静的メソッド、またはインスタンス メソッドにアタッチできます。F# 関数値は、デリゲート コンストラクターに引数として直接渡すことができます。静的メソッドの場合、クラスとメソッドの名前を使用してデリゲートを構築します。インスタンス メソッドの場合、オブジェクト インスタンスとメソッドを 1 つの引数で指定します。どちらの場合でも、メンバー アクセス演算子 (.) を使用します。
デリゲート型に対して Invoke メソッドを使用すると、カプセル化された関数が呼び出されます。デリゲートは、Invoke メソッドの名前をかっこを付けずに参照することで、関数値として渡すこともできます。
次のコードに、クラスの各種メソッドを表すデリゲートを作成するための構文を示します。メソッドが静的メソッドかインスタンス メソッドか、およびメソッドの引数がタプル形式かカリー化形式かに応じて、デリゲートを宣言して割り当てるための構文が多少、異なります。
type Test1() =
static member add(a : int, b : int) =
a + b
static member add2 (a : int) (b : int) =
a + b
member x.Add(a : int, b : int) =
a + b
member x.Add2 (a : int) (b : int) =
a + b
// Delegate1 works with tuple arguments.
type Delegate1 = delegate of (int * int) -> int
// Delegate2 works with curried arguments.
type Delegate2 = delegate of int * int -> int
let InvokeDelegate1 (dlg : Delegate1) (a : int) (b: int) =
dlg.Invoke(a, b)
let InvokeDelegate2 (dlg : Delegate2) (a : int) (b: int) =
dlg.Invoke(a, b)
// For static methods, use the class name, the dot operator, and the
// name of the static method.
let del1 : Delegate1 = new Delegate1( Test1.add )
let del2 : Delegate2 = new Delegate2( Test1.add2 )
let testObject = Test1()
// For instance methods, use the instance value name, the dot operator, and the instance method name.
let del3 : Delegate1 = new Delegate1( testObject.Add )
let del4 : Delegate2 = new Delegate2( testObject.Add2 )
for (a, b) in [ (100, 200); (10, 20) ] do
printfn "%d + %d = %d" a b (InvokeDelegate1 del1 a b)
printfn "%d + %d = %d" a b (InvokeDelegate2 del2 a b)
printfn "%d + %d = %d" a b (InvokeDelegate1 del3 a b)
printfn "%d + %d = %d" a b (InvokeDelegate2 del4 a b)
次のコードは、デリゲートのさまざまな操作方法のうちのいくつかを示しています。
type Delegate1 = delegate of int * char -> string
let replicate n c = String.replicate n (string c)
// An F# function value constructed from an unapplied let-bound function
let function1 = replicate
// A delegate object constructed from an F# function value
let delObject = new Delegate1(function1)
// An F# function value constructed from an unapplied .NET member
let functionValue = delObject.Invoke
List.map (fun c -> functionValue(5,c)) ['a'; 'b'; 'c']
|> List.iter (printfn "%s")
// Or if you want to get back the same curried signature
let replicate' n c = delObject.Invoke(n,c)
// You can pass a lambda expression as an argument to a function expecting a compatible delegate type
// System.Array.ConvertAll takes an array and a converter delegate that transforms an element from
// one type to another according to a specified function.
let stringArray = System.Array.ConvertAll([|'a';'b'|], fun c -> replicate' 3 c)
printfn "%A" stringArray
このコード例の出力は、次のようになります。
aaaaa
bbbbb
ccccc
[|"aaa"; "bbb"|]