デリゲート
デリゲート(delegate)とは英語では「委譲」という意味で、
ある関数から、別の関数へ処理を譲り渡すようなことが出来ます。
これはC#にある機能で、
C言語で言えば関数ポインタのようなイメージです。
delegateを用いることで「関数を値」として利用できるわけですが
F#では元々関数を値として利用できるため
F#でのdelegateは、次のような場合に用います。
1.C#などの他の.Net言語との相互運用性を持たせたい場合
2.F#から直接Cのコードを呼ぶためにコールバック関数を定義したい場合
デリゲートを利用するにはdelegateキーワードを用います。
デリゲートの利用
type dele = delegate of int -> int;;
let a = new dele(fun i -> i+1);;
printfn "%A" <| a.Invoke(3);;
1行目でint -> intという型の関数を受け取るdeleという型名のdelegateを宣言しています。
2行目で、deleに1足す関数を渡し、
3行目で、3を引数としてdele経由で関数を呼び出しています。
このようにdelegateに渡した関数を呼び出すにはInvokeメソッドを用います。
F#でdelegateを利用するのに多いのは2.のパターンだと思います。
これは、いわゆるイベントハンドラがdelegateとして定義されているからです。
ただ、既に定義されているイベントハンドラを使う分には
delegateだと意識する必要はありません。
delegateに関数が渡された場合、型があえば
F#コンパイラが自動的にdelegateに変換してくれるからです。
(参考:Foundations of F# p72)
デリゲートの合成(関数合成経由)
C#では、+演算子や-演算子がオーバーロードされているため
delegateを合成することが出来るのですが
ちょっと調べた感じでは、F#ではそういったことはできないようです。
しかし、F#ではそもそも関数合成が簡単にできるため
関数合成してからdelegateを作成すれば同じことが実現出来ます。
C#では合成したdelegateの呼び出し順序は不定でしたが
関数合成で作った関数は呼び出し順序を制御出来る分
F#ではより細かい制御が可能になります。
関数合成を利用したdelegateの合成
//>>は関数合成。2*x + 1を計算する関数
let twice_add1 = (( * ) 2) >> ((+)1);;
type dele = delegate of int -> int;;
let a = new dele(twice_add1);;
//コンパイル不可。C#相当コードでは2x+1になるか2*(x+1)になるかは不定、のはず
//let b = new dele((+)1) + new dele(( * ) 2);;
printfn "%d" <| a.Invoke(3);;