It's easy to write a function that adds two ints in F#:let add x y = x + yActually, it's the same as:let add (x:int) (y:int): int = x + yIf you need to make it generic so that it can take arguments of other type than int,you should use inline keyword:> let inline add x y = x + y;;val inline add :  x: ^a -> y: ^b ->  ^c    when ( ^a or  ^b) : (static member ( + ) :  ^a *  ^b ->  ^c)Then you can pass values of any type that has the + operator to add:> add 1 2;;val it : int = 3> add 1L 2L;;val it : int64 = 3L> add 1I 2I;;val it : System.Numerics.BigInteger = 3 However, it's not easy to write a generic function if you have to useliterals in the middle of an expression:> let inline inc x = x + 1;; val inline inc : x:int -> intx always evaluates to be of int since the literal 1 is of int. It would be cool if you could write something like the following pseudo-code:let inline inc (x:^T) = x + (1 :> ^T)In order to do so, F# provides NumericLiteralX (where X should be replaced with G, N, Z, ...):module NumericLiteralG =    let inline FromZero() = LanguagePrimitives.GenericZero    let inline FromOne() = LanguagePrimitives.GenericOne    let inline FromInt32 n =        let one = FromOne()        let zero = FromZero()        let iinc = if n > 0 then 1 else -1        let ginc = if n > 0 then one else -one        let rec loop i g =             if i = n then g            else loop (i + iinc) (g + ginc)        loop 0 zero Now you can make the inc function generic as follows:> let inline inc x = x + 1G;;val inline inc :  x: ^a ->  ^c    when ( ^a or  ^b) : (static member ( + ) :  ^a *  ^b ->  ^c) and          ^b : (static member get_One : ->  ^b)The obvious deficiency with NumericLiteralX, however, isFromInt32 can be horribly slow for a large number. For example, if you writea function that divides a number by 1000000:let inline divideByMillion x = x / 1000000Gthe loop in FromInt32 executes 1000000 times!Here I propose a better approach that has no such performance hit:type BigIntCast = BigIntCast with    static member inline (=>) (BigIntCast, x: int) = bigint x    static member inline (=>) (BigIntCast, x: uint32) = bigint x    static member inline (=>) (BigIntCast, x: int64) = bigint x    static member inline (=>) (BigIntCast, x: uint64) = bigint x    static member inline (=>) (BigIntCast, x: bigint) = x    static member inline (=>) (BigIntCast, x: single) = bigint x    static member inline (=>) (BigIntCast, x: double) = bigint x    static member inline (=>) (BigIntCast, x: decimal) = bigint x    static member inline (=>) (BigIntCast, x: byte[]) = bigint xtype NumericCast = NumericCast with    static member inline (=>) (NumericCast, _: sbyte) = sbyte    static member inline (=>) (NumericCast, _: byte) = byte    static member inline (=>) (NumericCast, _: int16) = int16    static member inline (=>) (NumericCast, _: uint16) = uint16    static member inline (=>) (NumericCast, _: int) = int    static member inline (=>) (NumericCast, _: uint32) = uint32    static member inline (=>) (NumericCast, _: int64) = int64    static member inline (=>) (NumericCast, _: uint64) = int64    static member inline (=>) (NumericCast, _: nativeint) = nativeint    static member inline (=>) (NumericCast, _: unativeint) = unativeint    static member inline (=>) (NumericCast, _: single) = single    static member inline (=>) (NumericCast, _: double) = double    static member inline (=>) (NumericCast, _: decimal) = decimal    static member inline (=>) (NumericCast, _: bigint) = (=>) BigIntCastlet inline (^>) t x = (NumericCast => x) tNow the inc function can be written as:> let inline inc x = x + (1 ^> x);;val inline inc :  x: ^a ->  ^c    when ( ^a or  ^b) : (static member ( + ) :  ^a *  ^b ->  ^c) and         (NumericCast or  ^a) : (static member ( => ) : NumericCast *  ^a ->                                                          int ->  ^b)   1 ^> x reads cast 1 to the same type as x.The results are the same as before:> inc 1;;val it : int = 2> inc 1L;;val it : int64 = 2L> inc 1I;;val it : System.Numerics.BigInteger = 2Type safety is enforced by the compiler:> inc 1;;  inc 1;;  ^^^C:\Users\junyoung\AppData\Local\Temp\stdin(8,1): error FS0043: No overloads match for method 'op_EqualsGreater'. The available overloads are shown below (or in the Error List window).Possible overload: 'static member NumericCast.( => ) : NumericCast:NumericCast * x: ^t -> ('a -> 'a) when  ^t : (static member get_One : ->  ^t)'. Type constraint mismatch. The type     string    is not compatible with type    'a    ... snip ...In summary, it's easy to use, fast and type-safe. Choose any three. :-)What do you think?The original idea of using an operator trick came from here.
Efficient generic type conversion between numeric types in F#
generics;f#;casting