Let\'s say I am solving a particular problem and come up with a function
let function parameter1 ... =
a lot of adding, multiplying & so on with a
One way to do it is combining inline
keyword and generic bits from LanguagePrimitives module:
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
While not ideal, and kind of bypassing your main question, you can add type annotations to force the compiler's hand:
let greatFunction (param1:int64) (param2:int64) : int64 = (param1+1)/(param2*2)
Now of course there are no implicit conversions in F#, so you will need to add L
to all numeric literals, but they will show up as compiler errors at least.
Here's an article on generic, numeric calculations in F#. In general, you have two options:
...or you can combine these techniques.
In your case, it sounds like static constraints will work.
A simple example from that article:
let inline halfSquare num =
let res = LanguagePrimitives.DivideByInt num 2
res * res
I think Generic Arithmetic is common problem in .NET languages. There are many articles explaining different approaches and very soon I will post another one explaining mine which is similar to the solution you posted.
Now, if you ask me if should you use it, I would say: as long as you understand what you are doing why not? I'm using it partially in production and have no issues at all, but because I care about run-time performance I use overloading to resolve everything at compile time. Then to speed up compile time I redefine basic math operators to operate in the same type, otherwise type signatures get really complicated and may take ages to compile.
There are more things to consider but for your specific problem here is a sample code:
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.