4

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?

Rob Bell
  • 3,542
  • 5
  • 28
  • 49
  • 1
    http://stackoverflow.com/a/3754961/2314532 will go a long way towards answering your question. – rmunn Apr 21 '17 at 08:50
  • 1
    Possible duplicate of [F# generics / function overloading syntax](http://stackoverflow.com/questions/30445828/f-generics-function-overloading-syntax) – spmdc Apr 21 '17 at 08:53
  • 2
    I don't think this question is a precise duplicate of [F# generics / function overloading syntax](http://stackoverflow.com/questions/30445828/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 Apr 21 '17 at 08:59
  • @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 Apr 21 '17 at 10:18

1 Answers1

6

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.

Community
  • 1
  • 1
rmunn
  • 34,942
  • 10
  • 74
  • 105