Some function usages don't compile when one side of an operator has a known type and the other doesn't. One example is with units of measure:
let inline multiplyWithFive x = 5. * x
type [<Measure>] myUnit
let test = multiplyWithFive 3.<myUnit> // Compiler error
5. * 3.<myUnit>
is clearly a valid expression, so this is surprising, especially considering that inline
functions generalize maximally in other cases:
let inline multiply a b = a * b
let test = multiply 5. 3.<myUnit> // Valid
This isn't limited to units of measure though. Say, I make a type that supports asymmetric multiplication with a float. It's incompatible with the multiplyWithFive
function, which arbitrarily infers its parameter as float
:
type BoxFloat =
{ Value : float }
static member inline (*) (lhs : float, rhs : BoxFloat) =
{ Value = lhs * rhs.Value }
let boxThree = { Value = 3. }
let test2 = multiplyWithFive boxThree // Compiler error
Again, 5. * boxThree
is a valid expression. But the automatic generalization doesn't seem to acknowledge that.
I can "fix" the first case with unit-of-measure-aware type annotations, but this restricts the underlying type for no apparent reason. If I actually need a more general function, I don't know how to stop the compiler from making up restrictions. If I explicitly name a generic parameter, it just refuses to keep it generic:
// Warning: This construct causes code to be less generic than indicated...
let inline multiplyWithFive (x : 'T) = 5. * x
What can I do about this? Is there some way to say that I do want the more generic version?