I'm confused on how to label a function as generic without an explicit type declaration like ('a -> 'a)
let add a b = a + b
This gives us
val add : a:int -> b:int -> int
However we can then immediately call
add "Hello " "World!"
and now the value of add is
val add : a:string -> b:string -> string
val it : string = "Hello World!"
If we then call
add 2 3 // then we get
error: This expression was expected to have type string but here has type int
How do I ensure that a function works on all types that say have the function (+)
defined
This is F#'s embarrassing skeleton in the closet.
Try this:
Fully generic! Clearly, function application and tuples work.
Now try this:
Hmmm, also generic. How about this:
Aha, as soon as I have a
(+)
in there, it becomesint
for some reason.Let's keep playing:
Hmmm, interesting. Turns out, if I make the function
inline
, then F# does consider it generic, but it also gives it this weirdwhen
clause, and my generic parameters have this strange^
symbol instead of the usual tick.This strange syntax is called "statically resolved type parameters" (see here for a somewhat coherent explanation), and the basic idea is that the function
(+)
requires its arguments to have astatic member (+)
defined. Let's verify:Now, the problem with this is that CLR does not support this kind of generic parameters (i.e. "any type, as long as it has such and such members"), so F# has to fake it and resolve these calls at compile time. But because of this, any methods that use this feature cannot be compiled to true generic IL methods, and thus have to be monomorphised (which is enabled by
inline
).But then, it would be very inconvenient to require that every function that uses arithmetic operators be declared
inline
, wouldn't it? So F# goes yet another extra step and tries to fix these statically resolved generic parameters based on how they are instantiated later in the code. That's why your function turns intostring->string->string
as soon as you use it with astring
once.But if you mark your function
inline
, F# wouldn't have to fix parameters, because it wouldn't have to compile the function down to IL, and so your parameters remain intact:If I understand you correctly, use inline:
Print:
Link: http://ideone.com/awsYNI
Make it inline