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
Overloading is typically the bugaboo of type-inferenced languages (at least when, like F#, the type system isn't powerful enough to contain type-classes). There are a number of choices you have in F#:
For your particular example, I would probably just use method overloading:
type MathOps =
static member sqrt_int(x:int) = x |> float |> sqrt |> int
static member sqrt_int(x:int64) = x |> float |> sqrt |> int64
let x = MathOps.sqrt_int 9
let y = MathOps.sqrt_int 100L
Yes, this can be done. Take a look at this hubFS thread.
In this case, the solution would be:
let inline retype (x:'a) : 'b = (# "" x : 'b #)
let inline sqrt_int (n:'a) = retype (sqrt (float n)) : 'a
Caveat: no compile-time type checking. I.e. sqrt_int "blabla"
compiles fine but you'll get a FormatException at runtime.
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
Not to take away from the correct answers already provided, but you can in fact use type constraints in pattern matching. The syntax is:
| :? type ->
Or if you want to combine type checking and casting:
| :? type as foo ->
This works:
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.