List
In an F# list we can store strings and ints. We can make a list of any element type. But after we create a list, it cannot be changed—it is immutable.
By accessing the Head
and Tail
, we can keep track of which elements we have processed. We can access other important properties like Length
on lists.
Head
and Tail
To start, we create an example string
list. We access the Length
of the list, which is 3. We then use the Head
and Tail
properties, which are important on the list.
Head
is the first element within the list. It is not a list itself. It is just an element.Tail
is another list, but it does not include the first element. It is the remainder of the list.// Create a list of strings with animal names. // ... Use semicolon to separate elements, not comma. let continents = ["Antarctica"; "Asia"; "Africa"] // It has three elements. let count = continents.Length printfn "%A" count // Head is the first element (a string here). let head = continents.Head printfn "%A" head // Tail is the list except for the first element. // ... It includes the second element onwards. let tail = continents.Tail printfn "%A" tail3 "Antarctica" ["Asia"; "Africa"]
For
-loopLet us create a list of 4 strings. Please note that the semicolon is used to separate elements in the list. A comma will create tuples within the list.
for-in
, do
-loop to access all the elements in the list. Each "animal" is a string
. We use printfn
to print these values.// Create a list of strings with animal names. let animals = ["cat"; "bird"; "fish"; "fox"] // Use loop to print all animals. for animal in animals do printfn "%A" animal"cat" "bird" "fish" "fox"
This is a more complex example. We introduce a recursive method printExample
. The rec keyword indicates it is a recursive (self-calling) method.
match
-with statement handles a nonempty list. It prints the head and then recurses on the tail.// Use recursion to print a list. // ... Match handles all cases of the list. // We handle the head and tail by printing the head. // We use recursion on the tail for the next elements. let rec printExample list = match list with | [] -> () | head :: tail -> printf "%d " head printExample tail // Test our recursive method. let numbers = [5; 10; 15; 20] printExample numbers5 10 15 20
List.append
An F# list cannot be appended to in-place. Instead, we can use List.append
to combine two lists together into a third list.
List.append
, we must have two lists. But we can create a one-element list to append just one element.let colors1 = ["blue"; "orange"] // Combine the two lists. // ... We append a 1-element list to append an element. let colors2 = List.append colors1 ["pink"] // Display before and after lists. printfn "%A" colors1 printfn "%A" colors2["blue"; "orange"] ["blue"; "orange"; "pink"]
With the "at" symbol we concatenate (combine) two lists. This is the same as the List.append
function, but with shorter syntax.
let materials = ["plastic"; "wood"] printfn "%A" materials // Add element to the beginning of the list. let materials2 = ["cement"] @ materials printfn "%A" materials2 // Add element to the end of the list. let materials3 = materials2 @ ["brick"] printfn "%A" materials3["plastic"; "wood"] ["cement"; "plastic"; "wood"] ["cement"; "plastic"; "wood"; "brick"]
With two ":" characters we add to the front of a list. This is a clearer syntax than using "at" or List.append
for this operation.
// Create a list with two elements. let lengths = [10; 10] printfn "%A" lengths // Add a value to the front. let lengths2 = 5 :: lengths printfn "%A" lengths2 // Add a new front. let lengths3 = 0 :: lengths2 printfn "%A" lengths3[10; 10] [5; 10; 10] [0; 5; 10; 10]
This example is more complex. It introduces a sortDouble
function that receives a list argument. It then pipelines that list through List.map
and List.sort
.
sortDouble
we receive an argument of name "x." We pass this list argument to List.map
.List.map()
uses a lambda expression, specified with "fun," to double
each element (with identifier "y").Sort()
is called after List.map
with that function's result. This sorts the doubled list in an ascending order (low to high).// This function doubles all elements in a list. // ... It then sorts them. let sortDouble x = x |> List.map (fun y -> y * 2) |> List.sort let items = [20; 10; 5; 50] // Double and sort our list elements. let result = sortDouble items printfn "%A" result[10; 20; 40; 100]
ResizeArray
With F# we can access all .NET types. The System.Collections.Generic.List
is often used. And F# provides a handy alias for it called ResizeArray
.
ResizeArray
underscore means a type is chosen automatically. We use Seq.toList
to convert to an F# list.// Create a System.Collections.Generic.List. // ... The ResizeArray is an aliased type. let resize = new ResizeArray<_>() resize.Add(300) resize.Add(600) resize.Add(0) // Convert our ResizeArray to a list. let result = Seq.toList resize // Display our list. printfn "%A" result.Length printfn "%A" result.Head3 300
Imagine a method acts on the first element of a list, and then must process the remainder of the list in later calls. We can just process Head
, and use Tail
to eliminate Head
.
Head
and Tail
we can reduce the list as we use it. This keeps track of our position within the list.With lists, we collect elements into groups. We can use higher-order procedures to act upon these lists. And Head
and Tail
help us reduce lists as we proceed.