Slices in F#

F# provides a powerful interface for working with sequences through lists and arrays. Let’s explore how to use these data structures.

open System

// Unlike arrays, lists in F# are immutable and can have any length.
// An empty list is represented by []
let emptyList: string list = []
printfn "uninit: %A %b %b" emptyList (emptyList = []) (emptyList.Length = 0)

// To create a list with initial values, we can use the list literal syntax
let s = ["a"; "b"; "c"]
printfn "init: %A" s

// We can access elements using indexing
printfn "get: %s" s.[2]

// len returns the length of the list
printfn "len: %d" s.Length

// We can add elements to a list using the cons operator '::'
// or the '@' operator for concatenating lists
let s2 = s @ ["d"]
let s3 = s2 @ ["e"; "f"]
printfn "add: %A" s3

// Lists can be copied using the List.map function
let c = List.map id s3
printfn "copy: %A" c

// We can slice lists using the '[start..end]' syntax
let l1 = s3.[2..4]
printfn "sl1: %A" l1

// This slices up to (but excluding) index 5
let l2 = s3.[0..4]
printfn "sl2: %A" l2

// And this slices from index 2 to the end
let l3 = s3.[2..]
printfn "sl3: %A" l3

// We can declare and initialize a list in a single line
let t = ["g"; "h"; "i"]
printfn "dcl: %A" t

// F# provides many useful functions for working with lists
let t2 = ["g"; "h"; "i"]
if t = t2 then
    printfn "t = t2"

// Lists can be composed into multi-dimensional data structures
let twoD = 
    [for i in 0..2 -> 
        [for j in 0..i -> i + j]]
printfn "2d: %A" twoD

When you run this program, you’ll see output similar to:

uninit: [] true true
init: ["a"; "b"; "c"]
get: c
len: 3
add: ["a"; "b"; "c"; "d"; "e"; "f"]
copy: ["a"; "b"; "c"; "d"; "e"; "f"]
sl1: ["c"; "d"; "e"]
sl2: ["a"; "b"; "c"; "d"; "e"]
sl3: ["c"; "d"; "e"; "f"]
dcl: ["g"; "h"; "i"]
t = t2
2d: [[0]; [1; 2]; [2; 3; 4]]

Note that while F# lists are different from arrays, they are rendered similarly by printfn with the %A format specifier.

F# also provides Array and Seq modules with many useful functions for working with arrays and sequences respectively. These can be used when you need mutable or lazy evaluated sequences.

Now that we’ve seen lists and arrays, we’ll look at F#’s other key data structure: maps.