F#

F# was designed by Don Syme at Microsoft Research, with a first release in 2005. It is a descendant of ML and OCaml, running on the same .NET platform as C#. It is functional first, but it has full support for classes and interfaces when you need them.

Paradigm: Object-Functional and Beyond

What Makes F# Special

  • Functional first. Values are immutable by default, functions are curried, and the pipe operator |> passes the result of one step into the next.
  • Type inference. Almost no type annotations are needed. The compiler infers types, including generic ones, from how values are used.
  • Discriminated unions and pattern matching. A union type lists its cases, each with data. match checks all cases, and incomplete matches produce a warning.
  • Units of measure. Numbers can carry units such as m or s. The compiler checks that you never add metres to seconds, and it computes derived units like m/s.
  • Objects when needed. Classes, interfaces and mutable fields exist, so F# can use any .NET library and be used from C#.
  • Computation expressions and type providers. Computation expressions (async { }, seq { }) are a general syntax for workflows, and type providers generate types from data sources.

Example: Unions, pipelines, units of measure and a class

type Shape =
    | Circle of float
    | Rect of float * float

let area shape =
    match shape with
    | Circle r -> System.Math.PI * r * r
    | Rect (w, h) -> w * h

let shapes = [ Circle 1.0; Rect (2.0, 3.0) ]

// pipeline: the result of each step feeds the next
let total = shapes |> List.map area |> List.sum
printfn "%.2f" total                    // 9.14

// units of measure
[<Measure>] type m
[<Measure>] type s
let distance = 100.0<m>
let time = 9.58<s>
let speed = distance / time             // float<m/s>
printfn "%.2f" (float speed)            // 10.44

// an object with mutable state
type Counter() =
    let mutable n = 0
    member _.Next() =
        n <- n + 1
        n

let c = Counter()
c.Next() |> ignore
printfn "%d" (c.Next())                 // 2

How It Works

  • Shape is a discriminated union, and area is inferred as Shape -> float with no annotation.
  • shapes |> List.map area |> List.sum reads like a sentence and needs no temporary variables.
  • distance / time has type float<m/s>. Writing distance + time would not compile. Units exist only at compile time and cost nothing at run time.
  • Counter is an ordinary class with a mutable field, so F# code can also be object-oriented and imperative.

History and Where It Is Used

F# is used in finance and data analysis, compilers and language tools, scientific computing and web back ends (with frameworks such as Giraffe and Fable, which compiles F# to JavaScript). It is often the first way a .NET team adopts functional programming, since it shares libraries and tooling with C#.

Learn More