F#にもジェネリックあります!今までもさらりと使ってたり使ってなかったりしますが、これはF#のコンパイラが最大限に空気を読んで、ジェネリックに出来そうなところは勝手にしてくれるからです。例えば以下のような関数を書いたとします。
let makeTuple x y = (x, y)
特に実用性のかけらもない関数ですが引数で渡された2つの値をタプルにして返します。こいつの定義は実は以下のようになってたりします。
'a -> 'b -> 'a * 'b
F#では型引数は、'aのようにシングルクォーテーションを使って表します。上記の定義では何かの型aを受け取って、何かの型bを受け取って'a * 'bのタプルを返すというものになります。このように、適当に関数を定義しておくと勝手にジェネリック型にしてくれます。試しにmakeTupleを使ってみます。
let makeTuple x y = (x, y) printfn "%A" <| makeTuple 1 "one" printfn "%A" <| makeTuple 2.1 1
makeTupleにintを渡したりfloatを渡したりstringを渡したりしています。実行結果は以下のようになります。
(1, "one") (2.1, 1)
ちなみに明示的にジェネリックだよということを関数の定義時に示すことも出来ます。makeTupleの場合以下のように定義出来ます。
let makeTuple (x : 'a) (y : 'b) = (x, y) let makeTuple<'T, 'U> (x : 'T) (y : 'U) = (x, y)
何パターンか書き方があるので、自分が馴染む書き方でいいと思いますが、コンパイラがかなり面倒みてるので自分で型引数を明示するということはあまりないと思います。強いて言えば型引数に制約をつけるときくらいかな。
例えば、型引数があるインターフェースを実装してないとダメという制約をつける場合には以下のように記述します。
// Showを持ってるというだけのインターフェース type IShowable = abstract Show : unit -> unit // TはIShowableじゃないとダメ let callShow<'T when 'T :> IShowable> (x : 'T) = // 制約でIShowableであると明示してるのでShowが呼べる x.Show() // さらっと新構文 // その場で型を定義してインスタンス生成。匿名型かな let s1 = { new obj() interface IShowable with override this.Show() = printfn "Showが呼ばれました" } // s1はIShowableを実装しているのでcallShowに渡せる callShow s1
「型引数 when 制約をつけたい型引数 :> 型名」のように制約を記述します。他にも色々制約をつけれたりするのですが、一番使うのはこの制約だと思います。他のは、MSDNで確認するといいと思うよ!
過去記事
- 手軽なスクリプト言語としてのF#
- 手軽なスクリプト言語としてのF# その2
- 手軽なスクリプト言語としてのF# その3
- 手軽なスクリプト言語としてのF# その4
- 手軽なスクリプト言語としてのF# その5
- 手軽なスクリプト言語としてのF# その6
- 手軽なスクリプト言語としてのF# その7
- 手軽なスクリプト言語としてのF# その8「レコード」
- 手軽なスクリプト言語としてのF# その9「クラス」
- 手軽なスクリプト言語としてのF# その10「継承・アブストラクトクラス」
- 手軽なスクリプト言語としてのF# その11「インターフェースと演算子のオーバーロード」
- 手軽なスクリプト言語としてのF# その12「ラムダ式とイベント」
- 手軽なスクリプト言語としてのF# その13「オブジェクト初期化子みたいなの」
- 手軽なスクリプト言語としてのF# その14「合成演算子とパイプ演算子」
- 手軽なスクリプト言語としてのF# その15「WPFしてみた」