3

I played around a little with F# today, wrote this:

let sq x = x * x

let i = sq 3
let d = sq 3.0

It compiles if I remove either the third or the fourth line, but not if both are present.

I get the error This expression should have type 'int', but has type 'float'.

Guy Coder
  • 24,501
  • 8
  • 71
  • 136
Johan Larsson
  • 17,112
  • 9
  • 74
  • 88

5 Answers5

6

The type inference works so that your function sq has type int -> int, because the first time compiler sees you use that function, you pass it an integer. So it assumes that sq is a function that takes an integer, and by definition of the function (x * x) it also returns an integer.

It is a bit complicated to define a fully generic arithmetic function in F#, but one way to do it is to make the function inline, like so:

let inline sq x = x * x

This way the body of your function will be inlined each time at the call site, so using an inlined sq function will be the same as substituting it's body every time it's used.

This approach has it's drawbacks, and I think it will be interesting for you to see this question.

Community
  • 1
  • 1
MisterMetaphor
  • 5,900
  • 3
  • 24
  • 31
2

Let-bound functions cannot be overloaded. In your specific case, you could use inline, which inlines the function body at compile time and can therefore choose an appropriate implementation of *, e.g.

let inline sq x = x * x
Frank
  • 2,738
  • 19
  • 30
2

The other answers are correct but they leave out an important part of the jigsaw: the fact that in F# there are no implicit conversions between, for example, ints and floats. This is the reason why your second call is in effect calling a different, non existent, overload with a float argument.

Kit
  • 2,089
  • 1
  • 11
  • 23
1

The function let sq x = x * x on default has type int -> int.

If you put it in the context of a let d = sq 3.0, F# compiler will infer its type as float -> float.

In any way, this function can have only one type signature, either int->int, or float->float.

Yin Zhu
  • 16,980
  • 13
  • 75
  • 117
1

This is a limitation in how the bindings are implemented. There are 2 alternatives.

Firstly, add inline to the declaration.

Secondly, use member bindings in a class and override the different types.

John Palmer
  • 25,356
  • 3
  • 48
  • 67