Gleam Lists

A list holds an ordered sequence of values, all of the same type. Lists in Gleam are immutable singly-linked lists — the same structure used in functional languages like Haskell and Erlang. They excel at sequential processing and pattern matching.

Creating Lists

let fruits = ["apple", "banana", "cherry"]
let primes = [2, 3, 5, 7, 11]
let empty  = []
let single = ["only one"]

All elements must share the same type. A list of String cannot contain an Int.

How Lists Work Internally


Singly-Linked List Diagram
──────────────────────────────────────────────────
[1, 2, 3, 4]

┌───┬──┐    ┌───┬──┐   ┌───┬──┐    ┌───┬────┐
│ 1 │ ─┼──▶│ 2 │ ─┼──▶│ 3 │ ─┼──▶│ 4 │ [] │
└───┴──┘    └───┴──┘   └───┴──┘    └───┴────┘
 head                               tail = []

Each element holds a value and a pointer to the next element. The last element points to an empty list []. This structure makes adding to the front fast — and everything else slower, which shapes how you write list algorithms.

Prepending to a List

Adding to the front of a list is instant — it creates a new head that points to the existing list:

let tail = [2, 3, 4]
let full = [1, ..tail]
// [1, 2, 3, 4]

Prepend Diagram
──────────────────────────────────────────────────
tail = [2, 3, 4]

After [1, ..tail]:
┌───┬──┐
│ 1 │ ─┼──▶  [2, 3, 4]   (original, unchanged)
└───┴──┘

The ..tail syntax spreads the existing list. The original list stays intact — Gleam creates a new list with 1 at the front.

The gleam/list Module


Frequently Used list Functions
──────────────────────────────────────────────────────────
Function                  │ Description
──────────────────────────┼───────────────────────────────
list.length(l)            │ Count of elements
list.first(l)             │ First element → Result
list.last(l)              │ Last element → Result
list.append(a, b)         │ Join two lists
list.reverse(l)           │ Reverse order
list.map(l, f)            │ Transform each element
list.filter(l, f)         │ Keep matching elements
list.fold(l, init, f)     │ Reduce to one value
list.contains(l, v)       │ Check if value exists
list.flatten(l)           │ Flatten nested lists
list.take(l, n)           │ First n elements
list.drop(l, n)           │ Drop first n elements
list.sort(l, compare)     │ Sort elements
list.zip(a, b)            │ Pair elements together

map — Transform Every Element

import gleam/list

let prices = [100, 200, 300]
let discounted = list.map(prices, fn(p) { p - 10 })
// [90, 190, 290]

map Diagram
──────────────────────────────────────────────────
[100, 200, 300]
  │    │    │
  ▼    ▼    ▼
 -10  -10  -10
  │    │    │
  ▼    ▼    ▼
[90, 190, 290]

filter — Keep Matching Elements

let scores = [45, 80, 60, 95, 30, 72]
let passing = list.filter(scores, fn(s) { s >= 60 })
// [80, 60, 95, 72]

fold — Reduce to One Value

let numbers = [1, 2, 3, 4, 5]
let total = list.fold(numbers, 0, fn(acc, n) { acc + n })
// total = 15

fold Step-by-Step
──────────────────────────────────────────────────
Start:  acc = 0

Step 1: acc = 0 + 1 = 1
Step 2: acc = 1 + 2 = 3
Step 3: acc = 3 + 3 = 6
Step 4: acc = 6 + 4 = 10
Step 5: acc = 10 + 5 = 15

Result: 15

Pattern Matching on Lists

The most powerful way to process a list is recursive pattern matching:

pub fn sum(numbers: List(Int)) -> Int {
  case numbers {
    []           -> 0
    [head, ..tail] -> head + sum(tail)
  }
}

// sum([1, 2, 3])
// = 1 + sum([2, 3])
// = 1 + 2 + sum([3])
// = 1 + 2 + 3 + sum([])
// = 1 + 2 + 3 + 0
// = 6

Recursive sum([1, 2, 3])
──────────────────────────────────────────────────
sum([1, 2, 3])
  head=1, tail=[2,3]
  1 + sum([2, 3])
       head=2, tail=[3]
       2 + sum([3])
            head=3, tail=[]
            3 + sum([])
                 → 0
            3 + 0 = 3
       2 + 3 = 5
  1 + 5 = 6

Checking and Searching

import gleam/list

let fruits = ["apple", "mango", "banana"]

let has_mango = list.contains(fruits, "mango")   // True
let count = list.length(fruits)                   // 3

let first = list.first(fruits)   // Ok("apple")
let last  = list.last(fruits)    // Ok("banana")

let empty_list = []
let nothing = list.first(empty_list)  // Error(Nil)

Sorting a List

import gleam/list
import gleam/int

let values = [5, 1, 8, 3, 9, 2]
let sorted = list.sort(values, int.compare)
// [1, 2, 3, 5, 8, 9]

Zipping Two Lists

let names  = ["Alice", "Bob", "Carol"]
let scores = [90, 78, 95]

let pairs = list.zip(names, scores)
// [#("Alice", 90), #("Bob", 78), #("Carol", 95)]

Zip Diagram
──────────────────────────────────────────────────
names:  ["Alice", "Bob",  "Carol"]
scores: [90,      78,     95    ]
         │         │       │
         ▼         ▼       ▼
pairs:  [#("Alice",90), #("Bob",78), #("Carol",95)]

Practical Example — Student Report

import gleam/list
import gleam/io
import gleam/int

pub fn class_average(scores: List(Int)) -> Int {
  let total = list.fold(scores, 0, fn(acc, s) { acc + s })
  let count = list.length(scores)
  total / count
}

pub fn top_scorers(scores: List(Int), threshold: Int) -> List(Int) {
  list.filter(scores, fn(s) { s >= threshold })
}

pub fn main() {
  let scores = [72, 88, 91, 65, 79, 95, 83]
  io.debug(class_average(scores))      // 81
  io.debug(top_scorers(scores, 85))    // [88, 91, 95]
}

Key Points


List Essentials
──────────────────────────────────────────────────
1. All elements must share the same type
2. Immutable — functions return new lists
3. Prepend with [new_item, ..existing_list]
4. Use list.map for transformation
5. Use list.filter for selection
6. Use list.fold for aggregation
7. Pattern match [head, ..tail] for recursion
8. list.first / list.last return Result types

Lists are the backbone of functional programming in Gleam. Mastering map, filter, and fold gives you the tools to process any collection without writing a single loop.

Leave a Comment

Your email address will not be published. Required fields are marked *