F# Cheatsheet


This cheatsheet glances over some of the common syntax of F# 3.0. If you have any comments, corrections, or suggested additions, please open an issue or send a pull request to https://github.com/dungpa/fsharp-cheatsheet.

Comments

Block comments are placed between (* and *). Line comments start from // and continue until the end of the line.

(* This is block comment *)

// And this is line comment

XML doc comments come after /// allowing us to use XML tags to generate documentation.

/// The `let` keyword defines an (immutable) value
let result = 1 + 1 = 2

Strings

F# string type is an alias for System.String type.

/// Create a string using string concatenation
let hello = "Hello" + " World"

Use verbatim strings preceded by @ symbol to avoid escaping control characters (except escaping " by "").

let verbatimXml = @"<book title=""Paradise Lost"">"

We don't even have to escape " with triple-quoted strings.

let tripleXml = """<book title="Paradise Lost">"""

Backslash strings indent string contents by stripping leading spaces.

let poem = 
    "The lesser world was daubed\n\
     By a colorist of modest skill\n\
     A master limned you in the finest inks\n\
     And with a fresh-cut quill."

Basic Types and Literals

Most numeric types have associated suffixes, e.g., uy for unsigned 8-bit integers and L for signed 64-bit integer.

let b, i, l, ul = 86uy, 86, 86L, 86UL

val b : byte = 86uy
val i : int = 86
val l : int64 = 86L
// val bigint : uint64 = 86UL

Other common examples are F or f for 32-bit floating-point numbers, M or m for decimals, and I for big integers.

let s, f, d, bi = 4.14F, 4.14, 0.7833M, 9999I

val s : float32 = 4.14f
val f : float = 4.14
val d : decimal = 0.7833M
val bi : System.Numerics.BigInteger = 9999

See Literals (MSDN) for complete reference.

Functions

The let keyword also defines named functions.

let negate x = x * -1 
let square x = x * x 
let print x = printfn "The number is: %d" x

let squareNegateThenPrint x = 
    print (negate (square x)) 

Pipe and composition operators

Pipe operator |> is used to chain functions and arguments together. Double-backtick identifiers are handy to improve readability especially in unit testing:

let ``square, negate, then print`` x = 
    x |> square |> negate |> print

This operator is essential in assisting the F# type checker by providing type information before use:

let sumOfLengths (xs : string []) = 
    xs 
    |> Array.map (fun s -> s.Length)
    |> Array.sum

Composition operator >> is used to compose functions:

let squareNegateThenPrint' = 
    square >> negate >> print

Recursive functions

The rec keyword is used together with the let keyword to define a recursive function:

let rec fact x =
    if x < 1 then 1
    else x * fact (x - 1)

Mutually recursive functions (those functions which call each other) are indicated by and keyword:

let rec even x =
   if x = 0 then true 
   else odd (x - 1)

and odd x =
   if x = 1 then true 
   else even (x - 1)

Pattern Matching

Pattern matching is often facilitated through match keyword.

let rec fib n =
    match n with
    | 0 -> 0
    | 1 -> 1
    | _ -> fib (n - 1) + fib (n - 2)

In order to match sophisticated inputs, one can use when to create filters or guards on patterns:

let sign x = 
    match x with
    | 0 -> 0
    | x when x < 0 -> -1
    | x -> 1

Pattern matching can be done directly on arguments:

let fst' (x, _) = x

or implicitly via function keyword:

/// Similar to `fib`; using `function` for pattern matching
let rec fib' = function
    | 0 -> 0
    | 1 -> 1
    | n -> fib' (n - 1) + fib' (n - 2)

For more complete reference visit Pattern Matching (MSDN).

Collections

Lists

A list is an immutable collection of elements of the same type.

// Lists use square brackets and `;` delimiter
let list1 = [ "a"; "b" ]
// :: is prepending
let list2 = "c" :: list1
// @ is concat    
let list3 = list1 @ list2   

// Recursion on list using (::) operator
let rec sum list = 
    match list with
    | [] -> 0
    | x :: xs -> x + sum xs

Arrays

Arrays are fixed-size, zero-based, mutable collections of consecutive data elements.

// Arrays use square brackets with bar
let array1 = [| "a"; "b" |]
// Indexed access using dot
let first = array1.[0]  

Sequences

A sequence is a logical series of elements of the same type. Individual sequence elements are computed only as required, so a sequence can provide better performance than a list in situations in which not all the elements are used.

// Sequences can use yield and contain subsequences
let seq1 = 
    seq {
        // "yield" adds one element
        yield 1
        yield 2

        // "yield!" adds a whole subsequence
        yield! [5..10]
    }

Higher-order functions on collections

The same list [ 1; 3; 5; 7; 9 ] or array [| 1; 3; 5; 7; 9 |] can be generated in various ways.

  • Using range operator ..

     let xs = [ 1..2..9 ]
    
  • Using list or array comprehensions

     let ys = [| for i in 0..4 -> 2 * i + 1 |]
    
  • Using init function

     let zs = List.init 5 (fun i -> 2 * i + 1)
    

Lists and arrays have comprehensive sets of higher-order functions for manipulation.

  • fold starts from the left of the list (or array) and foldBack goes in the opposite direction

    let xs' = Array.fold (fun str n -> 
                sprintf "%s,%i" str n) "" [| 0..9 |]
    
  • reduce doesn't require an initial accumulator

    let last xs = List.reduce (fun acc x -> x) xs
    
  • map transforms every element of the list (or array)

    let ys' = Array.map (fun x -> x * x) [| 0..9 |]
    
  • iterate through a list and produce side effects

    let _ = List.iter (printfn "%i") [ 0..9 ] 
    

All these operations are also available for sequences. The added benefits of sequences are laziness and uniform treatment of all collections implementing IEnumerable<'T>.

let zs' =
    seq { 
        for i in 0..9 do
            printfn "Adding %d" i
            yield i
    }

Tuples and Records

A tuple is a grouping of unnamed but ordered values, possibly of different types:

// Tuple construction
let x = (1, "Hello")

// Triple
let y = ("one", "two", "three") 

// Tuple deconstruction / pattern
let (a', b') = x

The first and second elements of a tuple can be obtained using fst, snd, or pattern matching:

let c' = fst (1, 2)
let d' = snd (1, 2)

let print' tuple =
    match tuple with
    | (a, b) -> printfn "Pair %A %A" a b

Records represent simple aggregates of named values, optionally with members:

// Declare a record type
type Person = { Name : string; Age : int }

// Create a value via record expression
let paul = { Name = "Paul"; Age = 28 }

// 'Copy and update' record expression
let paulsTwin = { paul with Name = "Jim" }

Records can be augmented with properties and methods:

type Person with
    member x.Info = (x.Name, x.Age)

Records are essentially sealed classes with extra topping: default immutability, structural equality, and pattern matching support.

let isPaul person =
    match person with
    | { Name = "Paul" } -> true
    | _ -> false

Discriminated Unions

Discriminated unions (DU) provide support for values that can be one of a number of named cases, each possibly with different values and types.

type Tree<'T> =
    | Node of Tree<'T> * 'T * Tree<'T>
    | Leaf


let rec depth = function
    | Node(l, _, r) -> 1 + max (depth l) (depth r)
    | Leaf -> 0

F# Core has a few built-in discriminated unions for error handling, e.g., Option and Choice.

let optionPatternMatch input =
   match input with
    | Some i -> printfn "input is an int=%d" i
    | None -> printfn "input is missing"

Single-case discriminated unions are often used to create type-safe abstractions with pattern matching support:

type OrderId = Order of string

// Create a DU value
let orderId = Order "12"

// Use pattern matching to deconstruct single-case DU
let (Order id) = orderId

Exceptions

The failwith function throws an exception of type Exception.

let divideFailwith x y =
    if y = 0 then 
        failwith "Divisor cannot be zero." 
    else x / y

Exception handling is done via try/with expressions.

let divide x y =
   try
       Some (x / y)
   with :? System.DivideByZeroException -> 
       printfn "Division by zero!"
       None

The try/finally expression enables you to execute clean-up code even if a block of code throws an exception. Here's an example which also defines custom exceptions.

exception InnerError of string
exception OuterError of string

let handleErrors x y =
   try 
     try 
        if x = y then raise (InnerError("inner"))
        else raise (OuterError("outer"))
     with InnerError(str) -> 
          printfn "Error1 %s" str
   finally
      printfn "Always print this."

Classes and Inheritance

This example is a basic class with (1) local let bindings, (2) properties, (3) methods, and (4) static members.

type Vector(x : float, y : float) =
    let mag = sqrt(x * x + y * y) // (1)
    member this.X = x // (2)
    member this.Y = y
    member this.Mag = mag
    member this.Scale(s) = // (3)
        Vector(x * s, y * s)
    static member (+) (a : Vector, b : Vector) = // (4)
        Vector(a.X + b.X, a.Y + b.Y)

Call a base class from a derived one.

type Animal() =
    member __.Rest() = ()

type Dog() =
    inherit Animal()
    member __.Run() =
        base.Rest()

Upcasting is denoted by :> operator.

let dog = Dog() 
let animal = dog :> Animal

Dynamic downcasting (:?>) might throw an InvalidCastException if the cast doesn't succeed at runtime.

let shouldBeADog = animal :?> Dog

Interfaces and Object Expressions

Declare IVector interface and implement it in Vector'.

type IVector =
    abstract Scale : float -> IVector

type Vector'(x, y) =
    interface IVector with
        member __.Scale(s) =
            Vector'(x * s, y * s) :> IVector
    member __.X = x
    member __.Y = y

Another way of implementing interfaces is to use object expressions.

type ICustomer =
    abstract Name : string
    abstract Age : int

let createCustomer name age =
    { new ICustomer with
        member __.Name = name
        member __.Age = age }

Active Patterns

Complete active patterns:

let (|Even|Odd|) i = 
    if i % 2 = 0 then Even else Odd

let testNumber i =
    match i with
    | Even -> printfn "%d is even" i
    | Odd -> printfn "%d is odd" i

Parameterized active patterns:

let (|DivisibleBy|_|) by n = 
    if n % by = 0 then Some DivisibleBy else None

let fizzBuzz = function 
    | DivisibleBy 3 & DivisibleBy 5 -> "FizzBuzz" 
    | DivisibleBy 3 -> "Fizz" 
    | DivisibleBy 5 -> "Buzz" 
    | i -> string i

Partial active patterns share the syntax of parameterized patterns but their active recognizers accept only one argument.

Compiler Directives

Load another F# source file into FSI.

#load "../lib/StringParsing.fs"

Reference a .NET assembly (/ symbol is recommended for Mono compatibility).

#r "../lib/FSharp.Markdown.dll"

Include a directory in assembly search paths.

#I "../lib"
#r "FSharp.Markdown.dll"

Other important directives are conditional execution in FSI (INTERACTIVE) and querying current directory (__SOURCE_DIRECTORY__).

#if INTERACTIVE
let path = __SOURCE_DIRECTORY__ + "../lib"
#else
let path = "../../../lib"
#endif
val result : bool

Full name: fsharpcheatsheet.result


 The `let` keyword defines an (immutable) value
val hello : string

Full name: fsharpcheatsheet.hello


 Create a string using string concatenation
val verbatimXml : string

Full name: fsharpcheatsheet.verbatimXml
val tripleXml : string

Full name: fsharpcheatsheet.tripleXml
val poem : string

Full name: fsharpcheatsheet.poem
val b : byte

Full name: fsharpcheatsheet.b
val i : int

Full name: fsharpcheatsheet.i
val l : int64

Full name: fsharpcheatsheet.l
val ul : uint64

Full name: fsharpcheatsheet.ul
val s : float32

Full name: fsharpcheatsheet.s
val f : float

Full name: fsharpcheatsheet.f
val d : decimal

Full name: fsharpcheatsheet.d
val bi : System.Numerics.BigInteger

Full name: fsharpcheatsheet.bi
val negate : x:int -> int

Full name: fsharpcheatsheet.negate
val x : int
val square : x:int -> int

Full name: fsharpcheatsheet.square
val print : x:int -> unit

Full name: fsharpcheatsheet.print
val printfn : format:Printf.TextWriterFormat<'T> -> 'T

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.printfn
val squareNegateThenPrint : x:int -> unit

Full name: fsharpcheatsheet.squareNegateThenPrint
val ( square, negate, then print ) : x:int -> unit

Full name: fsharpcheatsheet.( square, negate, then print )
val sumOfLengths : xs:string [] -> int

Full name: fsharpcheatsheet.sumOfLengths
val xs : string []
Multiple items
val string : value:'T -> string

Full name: Microsoft.FSharp.Core.Operators.string

--------------------
type string = System.String

Full name: Microsoft.FSharp.Core.string
module Array

from Microsoft.FSharp.Collections
val map : mapping:('T -> 'U) -> array:'T [] -> 'U []

Full name: Microsoft.FSharp.Collections.Array.map
val s : string
property System.String.Length: int
val sum : array:'T [] -> 'T (requires member ( + ) and member get_Zero)

Full name: Microsoft.FSharp.Collections.Array.sum
val squareNegateThenPrint' : (int -> unit)

Full name: fsharpcheatsheet.squareNegateThenPrint'
val fact : x:int -> int

Full name: fsharpcheatsheet.fact
val even : x:int -> bool

Full name: fsharpcheatsheet.even
val odd : x:int -> bool

Full name: fsharpcheatsheet.odd
val fib : n:int -> int

Full name: fsharpcheatsheet.fib
val n : int
val sign : x:int -> int

Full name: fsharpcheatsheet.sign
val fst' : x:'a * 'b -> 'a

Full name: fsharpcheatsheet.fst'
val x : 'a
val fib' : _arg1:int -> int

Full name: fsharpcheatsheet.fib'


 Similar to `fib`; using `function` for pattern matching
val list1 : string list

Full name: fsharpcheatsheet.list1
val list2 : string list

Full name: fsharpcheatsheet.list2
val list3 : string list

Full name: fsharpcheatsheet.list3
val sum : list:int list -> int

Full name: fsharpcheatsheet.sum
Multiple items
val list : int list

--------------------
type 'T list = List<'T>

Full name: Microsoft.FSharp.Collections.list<_>
val xs : int list
val array1 : string []

Full name: fsharpcheatsheet.array1
val first : string

Full name: fsharpcheatsheet.first
val seq1 : seq<int>

Full name: fsharpcheatsheet.seq1
Multiple items
val seq : sequence:seq<'T> -> seq<'T>

Full name: Microsoft.FSharp.Core.Operators.seq

--------------------
type seq<'T> = System.Collections.Generic.IEnumerable<'T>

Full name: Microsoft.FSharp.Collections.seq<_>
val xs : int list

Full name: fsharpcheatsheet.xs
val ys : int []

Full name: fsharpcheatsheet.ys
val i : int
val zs : int list

Full name: fsharpcheatsheet.zs
Multiple items
module List

from Microsoft.FSharp.Collections

--------------------
type List<'T> =
  | ( [] )
  | ( :: ) of Head: 'T * Tail: 'T list
  interface IEnumerable
  interface IEnumerable<'T>
  member GetSlice : startIndex:int option * endIndex:int option -> 'T list
  member Head : 'T
  member IsEmpty : bool
  member Item : index:int -> 'T with get
  member Length : int
  member Tail : 'T list
  static member Cons : head:'T * tail:'T list -> 'T list
  static member Empty : 'T list

Full name: Microsoft.FSharp.Collections.List<_>
val init : length:int -> initializer:(int -> 'T) -> 'T list

Full name: Microsoft.FSharp.Collections.List.init
val xs' : string

Full name: fsharpcheatsheet.xs'
val fold : folder:('State -> 'T -> 'State) -> state:'State -> array:'T [] -> 'State

Full name: Microsoft.FSharp.Collections.Array.fold
val str : string
val sprintf : format:Printf.StringFormat<'T> -> 'T

Full name: Microsoft.FSharp.Core.ExtraTopLevelOperators.sprintf
val last : xs:'a list -> 'a

Full name: fsharpcheatsheet.last
val xs : 'a list
val reduce : reduction:('T -> 'T -> 'T) -> list:'T list -> 'T

Full name: Microsoft.FSharp.Collections.List.reduce
val acc : 'a
val ys' : int []

Full name: fsharpcheatsheet.ys'
val iter : action:('T -> unit) -> list:'T list -> unit

Full name: Microsoft.FSharp.Collections.List.iter
val zs' : seq<int>

Full name: fsharpcheatsheet.zs'
val x : int * string

Full name: fsharpcheatsheet.x
val y : string * string * string

Full name: fsharpcheatsheet.y
val a' : int

Full name: fsharpcheatsheet.a'
val b' : string

Full name: fsharpcheatsheet.b'
val c' : int

Full name: fsharpcheatsheet.c'
val fst : tuple:('T1 * 'T2) -> 'T1

Full name: Microsoft.FSharp.Core.Operators.fst
val d' : int

Full name: fsharpcheatsheet.d'
val snd : tuple:('T1 * 'T2) -> 'T2

Full name: Microsoft.FSharp.Core.Operators.snd
val print' : 'a * 'b -> unit

Full name: fsharpcheatsheet.print'
val tuple : 'a * 'b
val a : 'a
val b : 'b
type Person =
  {Name: string;
   Age: int;}
  member Info : string * int

Full name: fsharpcheatsheet.Person
Person.Name: string
Person.Age: int
Multiple items
val int : value:'T -> int (requires member op_Explicit)

Full name: Microsoft.FSharp.Core.Operators.int

--------------------
type int = int32

Full name: Microsoft.FSharp.Core.int

--------------------
type int<'Measure> = int

Full name: Microsoft.FSharp.Core.int<_>
val paul : Person

Full name: fsharpcheatsheet.paul
val paulsTwin : Person

Full name: fsharpcheatsheet.paulsTwin
val x : Person
member Person.Info : string * int

Full name: fsharpcheatsheet.Person.Info
val isPaul : person:Person -> bool

Full name: fsharpcheatsheet.isPaul
val person : Person
type Tree<'T> =
  | Node of Tree<'T> * 'T * Tree<'T>
  | Leaf

Full name: fsharpcheatsheet.Tree<_>
union case Tree.Node: Tree<'T> * 'T * Tree<'T> -> Tree<'T>
union case Tree.Leaf: Tree<'T>
val depth : _arg1:Tree<'a> -> int

Full name: fsharpcheatsheet.depth
val l : Tree<'a>
val r : Tree<'a>
val max : e1:'T -> e2:'T -> 'T (requires comparison)

Full name: Microsoft.FSharp.Core.Operators.max
val optionPatternMatch : input:int option -> unit

Full name: fsharpcheatsheet.optionPatternMatch
val input : int option
union case Option.Some: Value: 'T -> Option<'T>
union case Option.None: Option<'T>
type OrderId = | Order of string

Full name: fsharpcheatsheet.OrderId
union case OrderId.Order: string -> OrderId
val orderId : OrderId

Full name: fsharpcheatsheet.orderId
val id : string

Full name: fsharpcheatsheet.id
val divideFailwith : x:int -> y:int -> int

Full name: fsharpcheatsheet.divideFailwith
val y : int
val failwith : message:string -> 'T

Full name: Microsoft.FSharp.Core.Operators.failwith
val divide : x:int -> y:int -> int option

Full name: fsharpcheatsheet.divide
namespace System
Multiple items
type DivideByZeroException =
  inherit ArithmeticException
  new : unit -> DivideByZeroException + 2 overloads

Full name: System.DivideByZeroException

--------------------
System.DivideByZeroException() : unit
System.DivideByZeroException(message: string) : unit
System.DivideByZeroException(message: string, innerException: exn) : unit
exception InnerError of string

Full name: fsharpcheatsheet.InnerError
exception OuterError of string

Full name: fsharpcheatsheet.OuterError
val handleErrors : x:'a -> y:'a -> unit (requires equality)

Full name: fsharpcheatsheet.handleErrors
val x : 'a (requires equality)
val y : 'a (requires equality)
val raise : exn:System.Exception -> 'T

Full name: Microsoft.FSharp.Core.Operators.raise
Multiple items
type Vector =
  new : x:float * y:float -> Vector
  member Scale : s:float -> Vector
  member Mag : float
  member X : float
  member Y : float
  static member ( + ) : a:Vector * b:Vector -> Vector

Full name: fsharpcheatsheet.Vector

--------------------
new : x:float * y:float -> Vector
val x : float
Multiple items
val float : value:'T -> float (requires member op_Explicit)

Full name: Microsoft.FSharp.Core.Operators.float

--------------------
type float = System.Double

Full name: Microsoft.FSharp.Core.float

--------------------
type float<'Measure> = float

Full name: Microsoft.FSharp.Core.float<_>
val y : float
val mag : float
val sqrt : value:'T -> 'U (requires member Sqrt)

Full name: Microsoft.FSharp.Core.Operators.sqrt
val this : Vector
member Vector.X : float

Full name: fsharpcheatsheet.Vector.X
member Vector.Y : float

Full name: fsharpcheatsheet.Vector.Y
member Vector.Mag : float

Full name: fsharpcheatsheet.Vector.Mag
member Vector.Scale : s:float -> Vector

Full name: fsharpcheatsheet.Vector.Scale
val s : float
val a : Vector
val b : Vector
property Vector.X: float
property Vector.Y: float
Multiple items
type Animal =
  new : unit -> Animal
  member Rest : unit -> unit

Full name: fsharpcheatsheet.Animal

--------------------
new : unit -> Animal
member Animal.Rest : unit -> unit

Full name: fsharpcheatsheet.Animal.Rest
Multiple items
type Dog =
  inherit Animal
  new : unit -> Dog
  member Run : unit -> unit

Full name: fsharpcheatsheet.Dog

--------------------
new : unit -> Dog
member Dog.Run : unit -> unit

Full name: fsharpcheatsheet.Dog.Run
val dog : Dog

Full name: fsharpcheatsheet.dog
val animal : Animal

Full name: fsharpcheatsheet.animal
val shouldBeADog : Dog

Full name: fsharpcheatsheet.shouldBeADog
type IVector =
  interface
    abstract member Scale : float -> IVector
  end

Full name: fsharpcheatsheet.IVector
abstract member IVector.Scale : float -> IVector

Full name: fsharpcheatsheet.IVector.Scale
Multiple items
type Vector' =
  interface IVector
  new : x:float * y:float -> Vector'
  member X : float
  member Y : float

Full name: fsharpcheatsheet.Vector'

--------------------
new : x:float * y:float -> Vector'
override Vector'.Scale : s:float -> IVector

Full name: fsharpcheatsheet.Vector'.Scale
val __ : Vector'
member Vector'.X : float

Full name: fsharpcheatsheet.Vector'.X
member Vector'.Y : float

Full name: fsharpcheatsheet.Vector'.Y
type ICustomer =
  interface
    abstract member Age : int
    abstract member Name : string
  end

Full name: fsharpcheatsheet.ICustomer
abstract member ICustomer.Name : string

Full name: fsharpcheatsheet.ICustomer.Name
abstract member ICustomer.Age : int

Full name: fsharpcheatsheet.ICustomer.Age
val createCustomer : name:string -> age:int -> ICustomer

Full name: fsharpcheatsheet.createCustomer
val name : string
val age : int
val __ : ICustomer
property ICustomer.Age: int
val testNumber : i:int -> unit

Full name: fsharpcheatsheet.testNumber
active recognizer Even: int -> Choice<unit,unit>

Full name: fsharpcheatsheet.( |Even|Odd| )
active recognizer Odd: int -> Choice<unit,unit>

Full name: fsharpcheatsheet.( |Even|Odd| )
val by : int
val fizzBuzz : _arg1:int -> string

Full name: fsharpcheatsheet.fizzBuzz
active recognizer DivisibleBy: int -> int -> unit option

Full name: fsharpcheatsheet.( |DivisibleBy|_| )
val path : string

Full name: fsharpcheatsheet.path
Fork me on GitHub