らくがき

2008/03/22

[F#] 動的に数値型Interfaceを対応付けて関数を動かす

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:

2 Comments:

  • 重箱の隅をつつくようですが、「数字型」ではなく「数値型」でしょう。
    コンピュータの世界では、数字と数値は別物ですから。

    正確な表現で、検索に引っかかりやすくしていただけるとうれしいかなと。

    By Anonymous Anonymous, at 9:44 AM  

  • まさに仰るとおりです(><b
    修正しました

    By Blogger BULE!, at 11:01 AM  

Post a Comment

<< Home