Type Inference
Prerequisites: Data types
F# is statically typed, yet you rarely write types. The compiler infers them from how values are used:
let width = 12 // int, because 12 is an int
let area w h = w * h // int -> int -> int, because * defaults to int
let greet name = "Hello, " + name // string -> string
printfn "%d" (area width 3)
printfn "%s" (greet "Ada")
36
Hello, Ada
In an editor with Ionide or Rider, hover over any name to see its inferred type — or turn on inline type hints.
Annotations
Add a type annotation with name: type when you want to document intent
or when the compiler needs help:
let half (x: float) : float = x / 2.0
let shout (text: string) = text.ToUpper() + "!"
printfn "%.1f" (half 5.0)
printfn "%s" (shout "hello")
2.5
HELLO!
The annotation after the parameters (: float) is the return type. In
shout, the annotation is required: the compiler reads code top to
bottom and needs to know text is a string before it can look up the
ToUpper method.
When inference needs help
let shout text = text.ToUpper()
main.fsx(1,18): error FS0072: The type of this expression could not be inferred before accessing its members. Add a type annotation, e.g. (expr: SomeType), to constrain the type before this point.
Method calls with . (like .ToUpper()) need a known type. Plain
functions and operators don't, which is one reason idiomatic F# prefers
functions such as String.length s over methods in pipelines.
Generic by default
If nothing constrains a type, F# makes the function generic:
let pair a b = (a, b)
let first (a, _) = a
printfn "%A" (pair 1 "one")
printfn "%A" (pair true 2.5)
printfn "%s" (first ("left", 99))
(1, "one")
(true, 2.5)
left
pair has the type 'a -> 'b -> 'a * 'b — 'a and 'b (read "alpha"
and "beta") are type parameters that stand for any type. You'll learn
more about generics in Level 2.
- Let inference do the work; annotate function parameters in public APIs, for method calls, and wherever it makes code clearer.
- When a type error is confusing, adding an annotation often moves the error to the line that's actually wrong.