Reputation: 12127
Let's assume this code:
let ToLower x = (string x).ToLower()
I can call it with:
ToLower 3
or:
ToLower 3.0
but not both since the first caller defines the type. so, I did this change, with my C# knowledge of generics:
let ToLower (x : 'a) = (string x).ToLower()
but same problem, it looks like the first caller is specializing the generic and that's it.
I'm looking for a solution where the compiler will generate n versions of the assignment, as needed based on the use cases.
What is the proper way to achieve this in F#?
Upvotes: 0
Views: 67
Reputation: 243126
F# type inference uses constraint solving where the use of a function later in the code can affect the type.
This is however only ever a problem when you are using some built-in primitives such as +
or string
, which are generic, but have special meaning for certain types. For those, you can use inline
(in which case, the code gets inlined and the compiler can handle the special meanings in the place where they are used). If you do not use inline
, the compiler will fix the type when you first use the function.
If you just define the function and never use it anywhere, then you get a type obj -> string
. This is because the compiler used obj
as the default type when there were no other constraints.
If you define the function and call it with ToLower 3
, the compiler adds a constraint that restricts the argument type to be int
(but then you cannot use it with anything else).
The case of string
is a bit odd, because you can convert any value to string - but if you want to do this for any value, you have to box
it first. Boxing is something that can be done on a generic value, so in this case, you can define this as a generic function:
let ToLower (x:'a) = (string (box x)).ToLower()
ToLower 3.0
ToLower 3
This works because the type of box
is 'a -> obj
without any other caveats (unlike the type of string
which is 'a -> string
, but with special handling of certain type parameters).
Upvotes: 3