The short version is, "Because that's how F# is designed".
The longer version is that if a function's type can't be generic (and you're correct that this one can't since not all types will necessarily inplement the +
operator), then F# has to pick a real type. The most common use case for the +
operator is adding integers, so F# defaults to assuming that +
is the integer-addition operator unless you tell it otherwise.
One way you could tell it otherwise is to put in a type annotation:
let add (str1 : string) str2 = str1 + str2
Note that you don't have to annotate both parameters: knowing that one side of the +
operator is a string is enough to let F# infer that the other side must be a string as well.
The other thing you could do is to make the function inline
, which will result in two things:
- F# will not compile this into a function call, but will actually insert the function's code into the calling locations, and
- Because of this, the F# compiler will be able to use different
+
operators in different calling locations, if needed.
That is, add 3 5
would become 3 + 5
which uses the integer-addition operator, and add "foo" "bar"
would become "foo" + "bar"
which uses the string-addition overload of +
.
The reasons why this works are gone into in more depth in questions like F# generics / function overloading syntax and Use of `inline` in F# (among others), so I won't get into them here.