Skip to content
Menu
Contents

Lists

Chapter 4 of 9

Many values of one type, and how to work with them.

Many values of the same type

A list holds any number of values of the same type:

nums = [1, 2, 3, 4]
names = ["Ada", "Grace"]
empty = []

A list never changes. Every list function gives you a new list. The three you will use most:

List.map(nums, \(n) -> n * 2)           # => [2, 4, 6, 8]
List.filter(nums, \(n) -> n % 2 == 0)   # => [2, 4]
List.foldl(nums, 0, \(sum, n) -> sum + n)   # => 10
  • map changes every item.
  • filter keeps the items that pass a test.
  • foldl walks the list and keeps a running result, starting from 0 here, and adds each item to it. The l is for left: it starts from the left.

Some lists have nothing to give. What is the first item of []? Bert does not crash. It answers with a value that says so:

List.head([1, 2, 3])    # => Ok(1)
List.head([])           # => Err(EmptyList)

Those Ok and Err values are called variants. They are next.

More list functions, such as List.reverse, List.concat, List.any and List.sort, are in the docs. There is no range or "repeat N times" helper. To count, you write a function that calls itself, as in Functions.

Chaining with |>

Say you want to keep the even numbers, times them by ten, and add them up. Nested calls read inside out:

List.foldl(
  List.map(List.filter(nums, \(n) -> n % 2 == 0), \(n) -> n * 10),
  0,
  \(sum, n) -> sum + n
)

The pipe |> lets you write the same thing top to bottom:

total = nums
  |> List.filter(\(n) -> n % 2 == 0)
  |> List.map(\(n) -> n * 10)
  |> List.foldl(0, \(sum, n) -> sum + n)    # => 60
  • The value goes in as the first argument. x |> f(a) is f(x, a).
  • Right after a |>, and only there, f() and f mean the same thing: nums |> List.length and nums |> List.length() are both List.length(nums).
  • Use |> when you have two or more steps; one step is just a normal call.