F# Generic methods and operators

f#, generics, type-inference

Solution

Standard .NET generics are not expressive enough to allow this kind of generic functions. The problem is that your code can work for any `'a` that supports the subtraction operator, but .NET generics cannot capture this constraint (they can capture interface constraints, but not member constraints).

However you can use F# `inline` functions and statically resolved type parameters that can have additional member constraints. I wrote an article that provides some more details about these.

Briefly, if you mark the function as `inline` and let the compiler infer the type, then you get (I removed explicit mention of the type parameter, as that makes the situation trickier):

> let inline genericDiff h (f: float -> _) x = 
>   ((f (x + h)) - (f (x - h))) / (h * 2.0);;

val inline genericDiff :
  float -> (float ->  ^a) -> float -> float
    when  ^a : (static member ( - ) :  ^a *  ^a -> float)

The compiler now used `^a` instead of `'a` to say that the parameter is resolved statically (during inlining) and it added a constraint saying that `^a` has to have a member `-` that takes two things and returns `float`.

Sadly, this is not quite what you want, because your `-` operator returns `Vect3` (and not `float` as the compiler inferred). I think the problem is that the compiler wants `/` operator with two arguments of the same type (while yours is `Vect3 * float`). You can use different operator name (for example, `/.`):

let inline genericDiff2 h (f: float -> _) x = 
  ((f (x + h)) - (f (x - h))) /. (h * 2.0);;

In this case, it will work on `Vect3` (if you rename the scalar division), but it won't easilly work on `float` (though there may be hacks that will make that possible - see this answer - though I would not consider that idiomatic F# and I'd probably try to find a way to avoid the need for that). Would it make sense to provide elementwise division and pass `h` as `Vect3` value, perhaps?

Problem

So far I've been quite impressed with the type inference in F#, however I have found something that it didn't really get: ``` //First up a simple Vect3 type type Vect3 = { x:float; y:float; z:float } with static member (/) (v1 : Vect3, s : float) = //divide by scalar, note that float {x=v1.x / s; y= v1.y /s; z = v1.z /s} static member (-) (v1 : Vect3, v2 : Vect3) = //subtract two Vect3s {x=v1.x - v2.x; y= v1.y - v2.y; z=v1.z - v2.z} //... other operators... //this works fine let floatDiff h (f: float -> float) x = //returns float ((f (x + h)) - (f (x - h)))/(h * 2.0) //as does this let vectDiff h (f: float -> Vect3) x = //returns Vect3 ((f (x + h)) - (f (x - h)))/(h * 2.0) //I'm writing the same code twice so I try and make a generic function: let genericDiff h (f: float -> 'a) x : 'a = //'a is constrained to a float ((f (x + h)) - (f (x - h)))/(h * 2.0) ``` When I try and build this last function a blue squiggly appears under the divide sign and the complier says the dreaded warning of "This construct causes code to be less generic than indicated by the type annotations. The type variable 'a has been constrained to be type 'float'". I provide the Vect3 with the suitable `/` operator for the function. Why is it warning me?

Original source

Related problems