Fsharp: sequence

By Xah Lee. Date: . Last updated: .

ai answer

xtodo

F# Sequences (Seq) Tutorial

Sequences in F# (seq<'T>) are lazy, forward-only collections that represent a series of values. They are one of the most powerful and memory-efficient data structures in F#.

1. What is a Sequence?

Comparison with other collections:

Feature seq<'T> list<'T> array<'T>
Evaluation Lazy Eager Eager
Memory Low Medium Low
Access Forward-only Random Random
Best for Large/infinite data, streaming Small fixed data Performance-critical

2. Creating Sequences

Sequence Expressions (most common)

// Empty sequence
let emptySeq = Seq.empty<int>

// Simple sequence
let numbers = seq { 1; 2; 3; 4; 5 }

// Range
let range1 = seq { 1 .. 10 }
let range2 = seq { 1 .. 2 .. 20 }  // step by 2

// With yield
let squares = seq {
    for i in 1..10 do
        yield i * i
}

// Or using yield! (for composing)
let combined = seq {
    yield! seq { 1..5 }
    yield! seq { 10..12 }
}

From other collections

let fromList = List.toSeq [1; 2; 3]
let fromArray = Array.toSeq [|1; 2; 3|]
let fromString = "hello" |> Seq.toArray  // char sequence

Infinite sequences

// Natural numbers
let naturals = Seq.initInfinite (fun i -> i + 1)

// Fibonacci
let fibs =
    Seq.unfold (fun (a, b) -> Some(a, (b, a + b))) (0, 1)

3. Core Operations

Transformation

let nums = seq { 1..10 }

nums |> Seq.map (fun x -> x * x)           // squares
nums |> Seq.filter (fun x -> x % 2 = 0)    // evens
nums |> Seq.choose (fun x -> if x % 2 = 0 then Some(x) else None)

Aggregation

Seq.sum nums
Seq.length nums                    // Note: forces evaluation
Seq.fold (+) 0 nums
Seq.reduce (+) nums                // same as fold but no initial value

Taking / Skipping

Seq.take 5 nums                    // first 5
Seq.skip 3 nums                    // skip first 3
Seq.takeWhile (fun x -> x < 6) nums
Seq.skipWhile (fun x -> x < 6) nums

Pairwise & Grouping

Seq.pairwise nums                  // [(1,2); (2,3); ...]
Seq.windowed 3 nums                // sliding window of 3
Seq.groupBy (fun x -> x % 3) nums

Sorting & Distinct

Seq.sort nums
Seq.sortBy (fun x -> -x) nums      // descending
Seq.distinct (seq {1; 2; 2; 3; 3})

4. Lazy Evaluation in Action

let expensive = seq {
    printfn "Computing..."
    for i in 1..1000000 do
        yield i
}

// Nothing happens yet
let firstFew = expensive |> Seq.take 5 |> Seq.toList
// "Computing..." prints only when we force evaluation

Important: Many operations are lazy. Use Seq.toList, Seq.toArray, or Seq.iter to force evaluation.

5. Common Patterns & Idioms

Generating data

// All primes (naive)
let isPrime n =
    seq { 2 .. int(sqrt(float n)) }
    |> Seq.forall (fun d -> n % d <> 0)

let primes =
    Seq.initInfinite (fun i -> i + 2)
    |> Seq.filter isPrime

Processing files lazily

open System.IO

let lines = File.ReadLines("large.log")  // returns seq<string>
lines
|> Seq.filter (fun line -> line.Contains "ERROR")
|> Seq.take 10
|> Seq.iter (printfn "%s")

Chaining operations (pipeline style)

seq { 1..100 }
|> Seq.filter (fun x -> x % 3 = 0)
|> Seq.map (fun x -> x * x)
|> Seq.sum

6. Performance Tips

  1. Avoid Seq.length on large/infinite sequences — it forces full evaluation.
  2. Prefer Seq.iter over converting to list when possible.
  3. Use Seq.cache if you need to iterate multiple times:
let cached = expensive |> Seq.cache
  1. Be careful with side effects in lazy sequences.

7. Advanced: Custom Sequence Generators

let rec allFiles dir = seq {
    yield! Directory.GetFiles(dir)
    for subdir in Directory.GetDirectories(dir) do
        yield! allFiles subdir
}

8. When to Use seq vs list

Practice Exercises

  1. Generate the first 10 even numbers using Seq.init.
  2. Write a function that returns the first n Fibonacci numbers.
  3. Process a large CSV lazily and compute average of a column.
  4. Create a sequence of all Pythagorean triples where a² + b² = c² with a,b,c ≤ 100.

Next steps: Explore Seq.zip, Seq.collect, Seq.concat, and the Seq module documentation on Microsoft Learn.

Would you like me to expand on any section (e.g., more examples, performance comparison, or integration with async sequences seq { ... } + task)?

Reference

fsharp data structure