4
votes

In F# I can combine strings with the + operator as follows:

let myString = "one" + "two"

But when I create a function that will accept two arguments and apply the same operator, and I put it in a module declared ahead of its usage, F# infers the types as integers:

module StringFunctions = 

let add str1 str2 = 
    str1 + str2

Calling the below gives me the build error, "The expressions was expected to have type 'int' but here has type 'string'":

let str3 = StringFunctions.add "three" "four"

Why does F# infer this as int? I assume that it can't be a generic method because not all types will implement the + operator, but why does it assume int?

1
stackoverflow.com/a/3754961/2314532 will go a long way towards answering your question. - rmunn
I don't think this question is a precise duplicate of F# generics / function overloading syntax, though it's pretty close. So I've given a short answer; read the linked question(s) for more detailed explanations. - rmunn
@spmdc - I think rmunn's answer is far more succinct and useful for someone new to F#. The question you reference is a leap too far. - Rob Bell

1 Answers

6
votes

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:

  1. F# will not compile this into a function call, but will actually insert the function's code into the calling locations, and
  2. 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.