Skip to content
AgileLogics
6 min read

Lists

Prerequisites: Tuples

A list is an immutable, ordered collection of values of the same type. Items are separated by semicolons (or new lines):

let primes = [2; 3; 5; 7]
let names =
    [ "Ada"
      "Grace"
      "Linus" ]
let empty: int list = []

printfn "%A" primes
printfn "%A" names
printfn "%d items, first is %d" primes.Length primes.Head
printfn "%A" primes.Tail
printfn "%b" empty.IsEmpty
printfn "%d" primes[2]
[2; 3; 5; 7]
["Ada"; "Grace"; "Linus"]
4 items, first is 2
[3; 5; 7]
true
5

Common mistake: commas

A comma makes a tuple, so [1, 2, 3] is a list containing one tuple, not three numbers:

printfn "%A" [1, 2, 3]
printfn "%d" [1, 2, 3].Length
printfn "%d" [1; 2; 3].Length
main.fsx(1,14): info FS3886: This list expression contains a single tuple element. Did you mean to use ';' instead of ',' to separate list elements?



main.fsx(2,14): info FS3886: This list expression contains a single tuple element. Did you mean to use ';' instead of ',' to separate list elements?

[(1, 2, 3)]
1
3

The compiler spots this mistake and prints a hint (FS3886) — but the code still compiles, so watch for it.

Building lists

let numbers = [1; 2; 3]

let withZero = 0 :: numbers          // "cons": add to the front
let combined = numbers @ [4; 5]      // concatenate
let range = [1 .. 5]
let evens = [0 .. 2 .. 10]
let squares = [ for i in 1 .. 5 -> i * i ]

printfn "%A" withZero
printfn "%A" combined
printfn "%A" range
printfn "%A" evens
printfn "%A" squares
printfn "%A" numbers
[0; 1; 2; 3]
[1; 2; 3; 4; 5]
[1; 2; 3; 4; 5]
[0; 2; 4; 6; 8; 10]
[1; 4; 9; 16; 25]
[1; 2; 3]

Lists are immutable: 0 :: numbers creates a new list and numbers is unchanged. This is cheap because the new list shares the old one's items — a list is a chain of linked cells, and :: just adds a cell at the front.

List comprehensions

Square brackets can contain code that yields items:

let multiplesOf3 = [ for i in 1 .. 20 do if i % 3 = 0 then yield i ]
let pairs = [ for a in 1 .. 2 do for b in ['x'; 'y'] -> (a, b) ]

printfn "%A" multiplesOf3
printfn "%A" pairs
[3; 6; 9; 12; 15; 18]
[(1, 'x'); (1, 'y'); (2, 'x'); (2, 'y')]

-> is short for do yield. Inside a list expression you can often leave out yield altogether ([ for i in 1 .. 3 do i * 2 ]).

Performance notes

Adding to the front (::) and reading the head are instant. Indexing (list[1000]), .Length, and appending with @ walk the list, so they get slower as the list grows. For random access, use an array (next lesson).

Practice

Build a list of the numbers from 1 to 30 that are divisible by 4 or 6 using a list comprehension, then print it and its length.

Show solution
let picked = [ for n in 1 .. 30 do if n % 4 = 0 || n % 6 = 0 then n ]
printfn "%A (%d numbers)" picked picked.Length
[4; 6; 8; 12; 16; 18; 20; 24; 28; 30] (10 numbers)