GetNumericAssociation なるもので動的に数値型Interfaceと対応付けられるみたい
(http://cs.hubfs.net/forums/thread/3129.aspx)
コード:
#light
open Math
open Math.GlobalAssociations
let Add (n1:'a) (n2:'a) =
let tn : INumeric<'a> = GetNumericAssociation<'a>()
tn.Add(n1, n2)
結果は次のように色々な数値型で動作させることが可能
Add 1 2
> val it : int = 3
Add 1. 2.
> val it : float = 3.0
Add 1L 2L
> val it : int64 = 3L
Add 1.f 2.f
> val it : float32 = 3.0f
デフォルトで float, int32, int64, bigint, float32, Complex, bignum が使えて、
他の型も登録することで選択肢に加えることができるんだって。
Add を他の関数で使うとこれまた同じ効果を得られる
let MyGenFunc (n1:'a) (n2:'a) (n3:'a) =
(Add (Add (Add n1 n2) (Add n1 n3)) (Add n2 n3))
結果:
MyGenFunc 1 2 3
> val it : int = 12
MyGenFunc 1. 2. 3.
> val it : float = 12.0
パフォーマンスを気にする場合は、ひとつの関数定義の中にすべてを含めてしまい、
let MyGenFunc (n1:'a) (n2:'a) (n3:'a) =
let tn : INumeric<'a> = GetNumericAssociation()
let inline (+) (n1:'a) (n2:'a) = tn.Add(n1, n2)
((n1 + n2) + (n1 + n3) + (n2 + n3))
演算子を適切に定義することで可読性を高めることもできる
らしい!
他の例としてはこんなの(http://cs.hubfs.net/forums/thread/3823.aspx)
let sumList (data:'a list) =
// get the F# 'INumeric' interface implementation for a type 'a
let num = GetNumericAssociation<'a>()
data |> List.fold_left (fun a b -> num.Add(a,b)) num.Zero;;
// sumList [1; 2; 3; 4; 5] ... returns 15
// sumList [1.1; 2.2; 3.3; 4.4; 5.5] ... returns 16.5
Labels: F# FSharp