Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

F# overly aggressive type inference?

So in doing some of the Project Euler problems, I want to be able to take the square root of integer values (int, long, bigint, etc), but Sqrt is only defined for floating-point values. So I've been writing my own little Newton-Raphson algorithm, and it's plenty accurate for what I need. However, I want to be able to call the built-in sqrt function on floating-point values. So I wrote something like this:

let inline dsqrt x =
    match box x with
    | :? float -> sqrt x
    | :? float32 -> sqrt x
    | _ -> p_dsqrt x

My function, obviously, is named "p_dsqrt". However, this function requires that the input have a Sqrt method defined, which sort of defeats the whole purpose. Am I missing some type constraint, or what?

like image 664
Lee Crabtree Avatar asked Jan 16 '23 11:01

Lee Crabtree


1 Answers

If you want to use the match, the inline keyword is not required but if you want to use an inline function and "hat types", use overloading instead of match:

type Sqrt = Sqrt with
    // Dummy overload in order to get the right types inferred (will never reach here)
    static member inline ($) (Sqrt, _:^t when ^t:null and ^t: struct) = id

    // Existing sqrt
    static member inline ($) (Sqrt, x:'a) :'a = sqrt x 

    // Your Newton-Raphson based sqrt's
    static member        ($) (Sqrt, x:int   ) = sqrtForInt    x
    static member        ($) (Sqrt, x:bigint) = sqrtForBigInt x 

let inline sqrt (x:'t) :'t = Sqrt $ x 

The return type will always be the same as the input type and the implementation of sqrt chosen will depend on that type. This selection will happen at compile-time which is the main difference with the match method which is resolved at run-time.

If I take out the dummy overload, it will have the same problem as your code: it will require the sqrt constraint.

like image 55
Gus Avatar answered Jan 21 '23 11:01

Gus