[Generics] Functions with generic parameter types
type T = T with static member ($) (T, n:int ) = int (sqrt (float n)) static member ($) (T, n:int64) = int64 (sqrt (float n)) let inline sqrt_int (x:'t) :'t = T $ x
It uses static constraints and overloading, which makes a compile-time lookup on the type of the argument.
The static constraints are automatically generated in presence of an operator (operator
$ in this case) but it can always be written by hand:
type T = T with static member Sqr (T, n:int ) = int (sqrt (float n)) static member Sqr (T, n:int64) = int64 (sqrt (float n)) let inline sqrt_int (x:'N) :'N = ((^T or ^N) : (static member Sqr: ^T * ^N -> _) T, x)
More about this here.
I am trying to figure out how to define a function that works on multiple types of parameters (e.g. int and int64). As I understand it, function overloading is not possible in F# (certainly the compiler complains). Take for example the following function.
let sqrt_int = function | n:int -> int (sqrt (float n)) | n:int64 -> int64 (sqrt (float n))
The compiler of course complains that the syntax is invalid (type constraints in pattern matching are not supported it seems), though I think this illustrates what I would like to achieve: a function that operates on several parameter types and returns a value of the according type. I have a feeling that this is possible in F# using some combination of generic types/type inference/pattern matching, but the syntax has eluded me. I've also tried using the :? operator (dynamic type tests) and when clauses in the pattern matching block, but this still produces all sorts errors.
As I am rather new to the language, I may very well be trying to do something impossible here, so please let me know if there is alternative solution.
Here's another way using runtime type checks...
let sqrt_int<'a> (x:'a) : 'a = // ' match box x with | :? int as i -> downcast (i |> float |> sqrt |> int |> box) | :? int64 as i -> downcast (i |> float |> sqrt |> int64 |> box) | _ -> failwith "boo" let a = sqrt_int 9 let b = sqrt_int 100L let c = sqrt_int "foo" // boom