F# Journey: Course 2 – Type Inference

By | April 2, 2014

Back to: F# Journey: Course 1 – Immutable Values

You probably know type inference already from C#. But in F# it’s like magic! You don’t have to define the type quite often. The compiler will automatically find out.

Let’s start with some examples:

let a = 1
// or
let plus a b = a + b

“a” is in that case of type “int”. The “plus” functions accepts 2 parameters (a,b) of type int and the return value is automatically treated as int. (I will cover functions in one of the next courses)

But if you want “double” instead of “int” then you can define the type explicitly.

let (a : double) = 4.0
// Or
let plus' (a : double) (b : double) = a + b

“a” and “b” and the function return value are of type double.

Now let’s output the values with the F# “printfn” function.

let a  = 4
printfn "Value of a: %A" a
printfn "Value of a: %d" a
printfn "Value of a: %s" a

The first and second printfn calls will work as expected. But the last one will not work. Your code will not compile at all!
The compiler brings this message: “This expression was expected to have type string
This because the printfn “%s” expects a value of type string. But in our case “a” is of type int.

No let’s have a look at our “plus” function.

let plus a b = a + b
printfn "Plus result: %A" (plus 1 2)
printfn "Plus result: %d" (plus 1 2)
printfn "Plus result: %s" (plus 1 2)

As you may guess, we get the same error again. But now let’s remove the first two printfn calls and try again.

let plus a b = a + b
printfn "Plus result: %s" (plus 1 2)

Yes.. it will still not work but this time we get a different error message: “The type ‘string’ does not match the type ‘int’
Because we want to output a string (%s) F# thinks that the return value of “plus” is of type string. The compiler changed the signature of the function from
int -> int -> int
int -> int -> string
Now we can even change the type of the parameters when calling the plus function to string -> string -> string

let plus a b = a + b
printfn "Plus result: %s" (plus "1" "2")

This compiles but the logic of this function doesn’t work as expected. The output is “Plus result: 12” and not 3. We are just concatenating two strings.
This is the right way how to call the printfn when the types are not defined.

let plus a b = a + b
printfn "Plus result: %d" (plus 1 2)

Even for custom types/records (will be covered in next courses) F# offers some nice features.
The first line in the code below defines a record type and the second line instantiates an object. The type “person” is inferred based on the properties “id” and “name”.

type person = { id : int; name : string }
let personRecord = { id = 1; name = "Darko" }

Next: F# Journey: Course 3 – Functions