3

私が特定の問題を解決していて、関数を思いついたとしましょう

let function parameter1 ... = 
     a lot of adding, multiplying & so on with a lot of 
     literals all over the place

パラメータがint型の場合、この関数は正常に機能します。しかし、どこかで 11 まで上げる必要があり、int64 または BigInteger への追加のプッシュが必要になります。それで、私は何をしますか?関数をコピーして貼り付け、名前を変更し、関数が int で動作する必要があるとコンパイラに思わせるすべてのリテラルの外観を探しに行きます。そして、これはひどいです。

これを行う方法はありますか:

let greatFunction param1 param2 = (param1+1)/(param2*2)

param1 と param2 は整数型の任意の組み合わせにできますか?

編集:

以下のkvbによる素晴らしいヒントを少し拡張して、次のことを思いつきました

module NumericLiteralG 

  let inline FromZero() = LanguagePrimitives.GenericZero
  let inline FromOne() = LanguagePrimitives.GenericOne
  let inline FromInt32 n =
    let rec loop nIn nOut = 
        if nIn>0 then loop (nIn - 1) (nOut + LanguagePrimitives.GenericOne)
        else nOut
    loop n LanguagePrimitives.GenericZero

使用すると少し醜くなります

let inline halfSquare num =
   let res = num / 2G
   res * res

let solve1 = halfSquare 5I 
let solve2 = halfSquare 5.0
let solve3 = halfSquare 5uy

ここで問題は、これを使用する必要があるかどうかです。そうでない場合、なぜですか?

4

4 に答える 4

5

Generic Arithmeticは、.NET言語でよくある問題だと思います。さまざまなアプローチを説明する記事がたくさんありますが、すぐに、あなたが投稿したソリューションに似た、私の説明をする別の記事を投稿します。

さて、あなたがそれを使うべきかどうか私に尋ねるなら、私は言うでしょう:あなたが何をしているのかを理解している限り、なぜそうではないのですか?部分的に本番環境で使用しており、まったく問題はありませんが、実行時のパフォーマンスを重視しているため、コンパイル時にすべてを解決するためにオーバーロードを使用しています。次に、コンパイル時間を短縮するために、基本的な数学演算子を同じ型で動作するように再定義します。そうしないと、型シグネチャが非常に複雑になり、コンパイルに時間がかかる場合があります。

考慮すべき点は他にもありますが、特定の問題については、サンプルコードを次に示します。

open System.Numerics

type FromInt = FromInt with
    static member ($) (FromInt, _:sbyte     ) = fun (x:int) -> sbyte      x
    static member ($) (FromInt, _:int16     ) = fun (x:int) -> int16      x
    static member ($) (FromInt, _:int32     ) = id
    static member ($) (FromInt, _:float     ) = fun (x:int) -> float      x
    static member ($) (FromInt, _:float32   ) = fun (x:int) -> float32    x
    static member ($) (FromInt, _:int64     ) = fun (x:int) -> int64      x
    static member ($) (FromInt, _:nativeint ) = fun (x:int) -> nativeint  x
    static member ($) (FromInt, _:byte      ) = fun (x:int) -> byte       x
    static member ($) (FromInt, _:uint16    ) = fun (x:int) -> uint16     x
    static member ($) (FromInt, _:char      ) = fun (x:int) -> char       x
    static member ($) (FromInt, _:uint32    ) = fun (x:int) -> uint32     x
    static member ($) (FromInt, _:uint64    ) = fun (x:int) -> uint64     x
    static member ($) (FromInt, _:unativeint) = fun (x:int) -> unativeint x
    static member ($) (FromInt, _:bigint    ) = fun (x:int) -> bigint     x
    static member ($) (FromInt, _:decimal   ) = fun (x:int) -> decimal    x
    static member ($) (FromInt, _:Complex   ) = fun (x:int) -> Complex(float x,0.0)  

let inline fromInt (a:int) : ^t = (FromInt  $  Unchecked.defaultof< ^t>) a

module NumericLiteralG =
    let inline FromZero() =LanguagePrimitives.GenericZero
    let inline FromOne() = LanguagePrimitives.GenericOne
    let inline FromInt32 (i:int)     = fromInt i


// This will reduce the number of types inferred, will reduce compile time too.
let inline (+) (a:^t) (b:^t) : ^t = a + b
let inline (-) (a:^t) (b:^t) : ^t = a - b
let inline (*) (a:^t) (b:^t) : ^t = a * b
let inline (/) (a:^t) (b:^t) : ^t = a / b
let inline (~-) (a:^t) : ^t = -a


let inline halfSquare num =
   let res = num / 2G
   res * res

let solve1 = halfSquare 5I 
let solve2 = halfSquare 5.0
let solve3 = halfSquare 5uy 

// Define more generic math functions.
于 2012-07-19T18:46:35.987 に答える
3

これは、F#での一般的な数値計算に関する記事です。一般に、2つのオプションがあります。

  • 静的メンバーの制約
  • グローバル数値アソシエーション(F#PowerPackで利用可能)

...またはこれらの手法を組み合わせることができます。

あなたの場合、静的制約が機能するように思えます。

その記事の簡単な例:

let inline halfSquare num =
   let res = LanguagePrimitives.DivideByInt num 2
   res * res
于 2012-07-19T13:57:45.943 に答える
3

これを行う 1 つの方法は、 LanguagePrimitivesモジュールinlineのキーワードとジェネリック ビットを組み合わせることです。

let inline greatFunction param1 param2 = 
    let one = LanguagePrimitives.GenericOne
    let two = one + one
    (param1+one)/(param2*two)

// Usage
let f1 = greatFunction 4 2
let f2 = greatFunction 4L 2L
let f3 = greatFunction 4I 2I
于 2012-07-19T13:59:38.780 に答える
0

理想的ではなく、主な質問を迂回するようなものですが、型注釈を追加してコンパイラーの手を強制することができます。

let greatFunction (param1:int64) (param2:int64) : int64 = (param1+1)/(param2*2)

もちろん、F#には暗黙の変換がないため、すべての数値リテラルに追加する必要がありますがL、少なくともコンパイラエラーとして表示されます。

于 2012-07-19T17:28:09.953 に答える